OS환경 : Oracle Linux 7.6 (64bit)
DB 환경 : Oracle Database 19.10.0.0
방법 : 오라클 19c 실행계획 변경 시 spm 적용 방법
테이블 ddl이나 특정 상황으로 인해 sql의 실행계획이 변경 될 수 있음
이 때 문제되는 sql id를 찾을 경우 spm을 이용해서 신속하게 기존 실행계획으로 변경시킬 수 있음
spm을 이용해 일단 빠르게 이전 실행계획으로 고정 시킨 다음
추후 쿼리에 원하는 방식으로 풀리게끔 힌트를 추가할 수 있음
0. 문제되는 쿼리 sql_id 확인
운영팀을 통해 sql_id를 받거나, ash 모니터링을 통해 문제 sql 식별
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
SQL>
select * from (
select
user_id,
sql_id,
event,
count(*) "cnt",
sum(wait_time) "wait_time",
sum(time_waited) "time_wait"
from v$active_session_history
where 1=1
and sample_time between sysdate - interval '1' minute and sysdate
--and sample_time between to_date('2022/11/28 09:00:00', 'yyyy/mm/dd hh24:mi:ss')
--and to_date('2022/11/28 09:05:00', 'yyyy/mm/dd hh24:mi:ss')
and session_type != 'background'
group by user_id, sql_id, event
order by count (*) desc
) a
where rownum <6;
|
1. 차일드 커서 확인 (실행계획 변경여부 확인 child_number 0이상이면 실행계획이 변경되었을 수 있음)
sql_id가 '4kdvdryf0774f'라고 가정함
(https://positivemh.tistory.com/372)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
--https://positivemh.tistory.com/372
SQL>
select sql_id,
PARSING_SCHEMA_NAME "USER",
PLAN_HASH_VALUE,
OPTIMIZER_MODE,
child_number,
parse_calls,
USERS_OPENING,
USERS_EXECUTING,
loads,
executions,
invalidations,
decode(sign(invalidations), 1, (loads-invalidations), 0) reloads,
FIRST_LOAD_TIME,
LAST_LOAD_TIME
from v$sql
where sql_id='4kdvdryf0774f'
and sql_text not like '%v$sql%';
|
2_1. 동일 sql_id의 다른 plan_hash_value 확인
1
2
3
|
SQL>
select distinct sql_id, sql_plan_hash_value from dba_hist_active_sess_history
where sql_id = '4kdvdryf0774f';
|
------------------하드파싱 쿼리일 경우 확인 사항---------------------------------
2_2. 2_1결과가 다른 plan_hash_value가 나오지 않는경우 하드파싱 쿼리일 가능성이 있음,
v$sql이나 dba_hist_active_sess_history에서 sql_id를 이용해 sql_text 확인 후 like 절로 비슷한 쿼리가 있는지 검색
1
2
3
|
SQL>
select sql_id, sql_fulltext, plan_hash_value from v$sql
where sql_id = '4kdvdryf0774f';
|
2_3. sql text로 비슷한 쿼리 검색
1
2
3
|
SQL>
select sql_id, sql_text, plan_hash_value from v$sql
where sql_text like '%selct * from%';
|
2_4. 비슷한 쿼리의 sql_id를 찾았다면 해당쿼리 플랜 확인
1
|
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('05qj3sk9fssgw', null, 'ADVANCED ALLSTATS LAST'));
|
2_5. 이전 플랜으로 실행될수 있게끔 힌트 작성 후 AP팀에 전달
------------------하드파싱 쿼리일 경우 확인 사항---------------------------------
3. sql_id 실행계획 plan_hash_value 별 성능 확인
1
2
3
4
5
6
7
8
|
SQL>
select a.instance_number inst_id, a.snap_id,a.plan_hash_value, to_char(begin_interval_time,'dd-mon-yy hh24:mi') btime,
abs(extract(minute from (end_interval_time-begin_interval_time)) + extract(hour from (end_interval_time-begin_interval_time))*60 + extract(day from (end_interval_time-begin_interval_time))*24*60) minutes,
executions_delta executions, round(ELAPSED_TIME_delta/1000000/greatest(executions_delta,1),4) "avg duration (sec)"
from dba_hist_sqlstat a, dba_hist_snapshot b
where sql_id='4kdvdryf0774f' and a.snap_id=b.snap_id
and a.instance_number=b.instance_number
order by snap_id desc, a.instance_number;
|
4_1. spm에 sql_id 와 plan_hash_value로 baseline 등록
1
2
3
4
5
6
7
8
9
10
11
12
13
|
SQL>
set serveroutput on
declare
ret number;
begin
ret := dbms_spm.load_plans_from_cursor_cache(
sql_id => '4kdvdryf0774f',
plan_hash_value => 3177216401,
enabled => 'YES',
fixed => 'YES');
dbms_output.put_line('LOAD PLANS : '|| ret);
end;
/
|
4_2. spm 안되면 sqlset 이용(cursor에 없을경우 4_1 실행결과가 Load : 0으로 나옴)
(3에서 확인한 좋은성능일때의 snap_id를 dbms_sqltune.select_workload_repository에 넣어줘야함)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
SQL>
exec dbms_sqltune.create_sqlset('sts_4kdvdryf0774f_3177216401');
set serveroutput on
declare
baseline_cursor dbms_sqltune.sqlset_cursor;
x pls_integer;
begin
open baseline_cursor for
select value(p) from table (dbms_sqltune.select_workload_repository(300120,300125,'sql_id='||CHR(39)||'4kdvdryf0774f'||CHR(39)||' and plan_hash_value=3177216401',NULL,NULL,NULL,NULL,NULL,NULL,'ALL')) p;
dbms_sqltune.load_sqlset('sts_4kdvdryf0774f_3177216401', baseline_cursor);
x := dbms_spm.load_plans_from_sqlset(sqlset_name => 'sts_4kdvdryf0774f_3177216401', fixed => 'YES', enabled => 'YES');
dbms_output.put_line(to_char(x) || ' plan baselines loaded');
end;
/
|
5. 등록한 sql plan baseline 확인
1
2
3
4
5
|
SQL>
select sql_handle, plan_name, executions, to_char(created, 'YYYY/MM/DD HH24:MI:SS') created, accepted, fixed
from dba_sql_plan_baselines
--where sql_text like 'with /* Trend%';
where signature in ( select exact_matching_signature FROM v$sql WHERE sql_id='4kdvdryf0774f');
|
참고1. baseline 변경
1
2
3
4
5
6
7
8
9
10
11
12
|
SQL>
declare
ret number;
begin
ret := dbms_spm.alter_sql_plan_baseline(
sql_handle => 'SQL_e18f9b7e02f01359',
plan_name => 'SQL_PLAN_f33wvgs1g04ut5ac47e2d',
attribute_name => 'fixed',
attribute_value => 'NO');
dbms_output.put_line('PLANS ALTERED: ' || ret);
END;
/
|
참고2. baseline 제거
1
2
3
4
5
6
7
8
9
10
11
|
SQL>
set serveroutput on
declare
ret number;
begin
ret := dbms_spm.drop_sql_plan_baseline(
sql_handle => 'SQL_e18f9b7e02f01359',
plan_name => 'SQL_PLAN_f33wvgs1g04ut5ac47e2d');
dbms_output.put_line('DROP PLANS : '|| ret);
end;
/
|
참고3. 커서 플랜 확인
1
|
SQL> select * from table(dbms_xplan.display_cursor('4kdvdryf0774f', null, 'ADVANCED ALLSTATS LAST'));
|
참고4. awr 플랜 확인
1
|
SQL> select * from table(dbms_xplan.display_awr('4kdvdryf0774f', 3177216401, format=>'ADVANCED ALLSTATS LAST'));
|
참조 : https://blogs.oracle.com/optimizer/post/does-sql-plan-management-require-pack-license
https://docs.oracle.com/en/database/oracle/oracle-database/19/tgsql/managing-sql-plan-baselines.html
https://positivemh.tistory.com/217
https://www.funoracleapps.com/2022/01/how-can-we-run-sql-tuning-advisor-for.html
'ORACLE > Performance Tuning ' 카테고리의 다른 글
오라클 19c 하드파싱 쿼리 플랜 변경 의심시 조치방법 (0) | 2022.10.09 |
---|---|
오라클 19c cursor_sharing 테스트 (0) | 2022.08.08 |
오라클 11gR2 파티션 변경(split, drop, add) 시 커서 상태 변화 확인 (0) | 2022.07.18 |
오라클 19c itas 시 full scan과 index scan 속도 비교 테스트 (2) | 2022.04.13 |
오라클 19c 실행계획 비교 DBMS_XPLAN.COMPARE_PLANS (0) | 2022.03.21 |