1. 程式人生 > >使用hint優化Oracle的運行計劃 以及 SQL Tune Advisor的使用

使用hint優化Oracle的運行計劃 以及 SQL Tune Advisor的使用

dual sss 嚴重 acl lang put rec fix values

背景:

某表忽然出現查詢很緩慢的情況。cost 100+ 秒以上;嚴重影響生產。


原SQL:

explain plan for 
select * from (
select ID id,RET_NO retNo, FROM_SYS fromSy, TO_SYS toSys, COMMAND_CODE commandCode, COMMAND, STATUS, 
EXT_CODE, ORIGN_CODE orignCode,error_message errorMessage, RE_F, RET_MSG retMsg 
from interface_table where ((command_code in(‘AASSS‘) 
			and  status in(‘F‘,‘E‘) and (re_f = ‘N‘) and FROM_SYS = ‘MEE‘)
			or (COMMAND_CODE in(‘XXXX‘,‘XXXX9‘) and FROM_SYS = ‘EXT‘ and RE_F = ‘N‘)
			) and MOD(id, 1) = 0  order by id) where rownum <= 100  ;
查看其運行計劃:
SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY(‘PLAN_TABLE‘));
Plan hash value: 1871549687
?
----------------------------------------------------------------------------------------------------
| Id? | Operation???????????????????? | Name?????????????? | Rows? | Bytes | Cost (%CPU)| Time???? |
----------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT????????????? |??????????????????? |??? 99 |?? 382K|?? 637?? (1)| 00:00:08 |
|*? 1 |? COUNT STOPKEY??????????????? |??????????????????? |?????? |?????? |??????????? |????????? |
|?? 2 |?? VIEW??????????????????????? |??????????????????? |?? 100 |?? 386K|?? 637?? (1)| 00:00:08 |
|*? 3 |??? TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE??? |?? 355 | 55735 |?? 637?? (1)| 00:00:08 |
|*? 4 |???? INDEX FULL SCAN?????????? | PK_INTERFACE_TABLE |? 1439 |?????? |?? 280?? (2)| 00:00:04 |
----------------------------------------------------------------------------------------------------


優化後的SQL:

explain plan for 
select * from (
select /*+ index(INT_TABLE IX_INT_TABLE_2)*/ ID id,RET_NO retNo, FROM_SYS fromSy, TO_SYS toSys, COMMAND_CODE commandCode, COMMAND, STATUS, 
EXT_CODE, ORIGN_CODE orignCode,error_message errorMessage, RE_F, RET_MSG retMsg 
from interface_table where ((command_code in(‘AASSS‘) 
			and  status in(‘F‘,‘E‘) and (re_f = ‘N‘) and FROM_SYS = ‘MEE‘)
			or (COMMAND_CODE in(‘XXXX‘,‘XXXX9‘) and FROM_SYS = ‘EXT‘ and RE_F = ‘N‘)
			) and MOD(id, 1) = 0 order by id) where rownum <= 100  ;
查看其運行計劃:

SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY(‘PLAN_TABLE‘));
Plan hash value: 3625182869
?
--------------------------------------------------------------------------------------------------------
| Id? | Operation?????????????????????? | Name???????????????? | Rows? | Bytes | Cost (%CPU)| Time???? |
--------------------------------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT??????????????? |????????????????????? |??? 99 |?? 382K| 19105?? (1)| 00:03:50 |
|*? 1 |? COUNT STOPKEY????????????????? |????????????????????? |?????? |?????? |??????????? |????????? |
|?? 2 |?? VIEW????????????????????????? |????????????????????? |?? 356 |? 1376K| 19105?? (1)| 00:03:50 |
|*? 3 |??? SORT ORDER BY STOPKEY??????? |????????????????????? |?? 356 | 55892 | 19105?? (1)| 00:03:50 |
|?? 4 |???? CONCATENATION?????????????? |????????????????????? |?????? |?????? |??????????? |????????? |
|*? 5 |????? TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE????? |??? 69 | 10833 |? 9552?? (1)| 00:01:55 |
|*? 6 |?????? INDEX RANGE SCAN????????? | IX_INTERFACE_TABLE_2 | 77145 |?????? |??? 99?? (0)| 00:00:02 |
|*? 7 |????? TABLE ACCESS BY INDEX ROWID| INTERFACE_TABLE????? |?? 287 | 45059 |? 9552?? (1)| 00:01:55 |
|*? 8 |?????? INDEX RANGE SCAN????????? | IX_INTERFACE_TABLE_2 | 77145 |?????? |??? 99?? (0)| 00:00:02 |
--------------------------------------------------------------------------------------------------------


比較:

查看運行計劃。原來是使用 full scan - 當數據量大時很慢。優化後oracle優先走range scan,hint 的 index 是未處理標識字段的索引,正常情況下這個數據集合相對較小--------所以能夠達到優化目的。

詳細情況詳細分析,我們必需要看實際的表存的業務數據。分析其業務關系找到最小業務集合。後者要看懂運行計劃,依據rows, bytes, cost, time 找到最優項目。這個分析順序不能倒置。

問題:為何使用 rownum 後,oracle運行計劃會走full scan?


轉:怎樣看懂運行計劃:http://jadethao.iteye.com/blog/1613943


====? section2 ====

http://blog.chinaunix.net/uid-77311-id-3233190.html

環境: OS:Red Hat Linux As 5 DB:10.2.0.4 ? Oracle通過STA給出某個SQL運行建議,以下通過一個測試檢查Oracle給出的優化建議是否正確. ? 1.建表並生成測試數據 SQL> create table tb_test(id number not null,name varchar2(30)); Table created. SQL> create index idx_tb_test on tb_test(id); Index created. SQL> declare
begin
? for i in 1 .. 100000 loop
??? insert into tb_test values (i, ‘test‘);
??? commit;
? end loop;
end;
/
? 2.分析表 begin
? dbms_stats.gather_table_stats(ownname => ‘SCOTT‘, tabname => ‘TB_TEST‘);
end;

3.編造一個運行計劃不正確的SQL

select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1

我們知道在ID列上有索引,這個SQL走索引是正確的運行計劃,但這裏強制oracle走全表掃描,然後通過STA,看oracle給出的運行計劃是否正確.

4.創建TUNING_TASK並運行

declare
? l_task_name varchar2(30);
? l_sql?????? clob;
begin
? l_sql?????? := ‘select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1‘;
? l_task_name := DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_text??? => l_sql,
???????????????????????????????????????????????? user_name?? => ‘SCOTT‘,
???????????????????????????????????????????????? scope?????? => ‘COMPREHENSIVE‘,
???????????????????????????????????????????????? time_limit? => 60,
???????????????????????????????????????????????? task_name?? => ‘task_name01‘,
???????????????????????????????????????????????? description => null);
dbms_sqltune.Execute_tuning_task(task_name => ‘task_name01‘);
end;

5.查看oracle給出的優化建議

SQL> set serveroutput on;
SQL> set long 999999999;
SQL> SELECT DBMS_SQLTUNE.REPORT_TUNING_TASK(‘task_name01‘) FROM DUAL;

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------
GENERAL INFORMATION SECTION
-------------------------------------------------------------------------------
Tuning Task Name????????????????? : task_name01
Tuning Task Owner???????????????? : SYS
Scope???????????????????????????? : COMPREHENSIVE
Time Limit(seconds)?????????????? : 60
Completion Status???????????????? : COMPLETED
Started at??????????????????????? : 06/03/2012 00:07:58
Completed at????????????????????? : 06/03/2012 00:07:59
Number of SQL Profile Findings??? : 1


DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_TASK_NAME01‘)
--------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Schema Name: SCOTT
SQL ID???? : ga3q5tqjgsj5u
SQL Text?? : select/*+ full(t)*/ count(1) from scott.tb_test t where t.id=1

-------------------------------------------------------------------------------
FINDINGS SECTION (1 finding)
-------------------------------------------------------------------------------

1- SQL Profile Finding (see explain plans section below)
--------------------------------------------------------

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘MY_TASK_NAME01‘)
--------------------------------------------------------------------------------
? A potentially better execution plan was found for this statement.

? Recommendation (estimated benefit: 84.11%)
? ------------------------------------------
? - Consider accepting the recommended SQL profile.
??? execute dbms_sqltune.accept_sql_profile(task_name => ‘task_name01‘,
??????????? replace => TRUE);

-------------------------------------------------------------------------------
EXPLAIN PLANS SECTION
-------------------------------------------------------------------------------

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------

1- Original With Adjusted Cost
------------------------------
Plan hash value: 1372292586

--------------------------------------------------------------------------------

| Id? | Operation????????? | Name????? | Rows? | Bytes | Cost (%CPU)| Time???? |

--------------------------------------------------------------------------------

-- 當前的運行計劃
DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------
|?? 0 | SELECT STATEMENT?? |?????????? |???? 1 |???? 4 |???? 6?? (0)| 00:00:01 |

|?? 1 |? SORT AGGREGATE??? |?????????? |???? 1 |???? 4 |??????????? |????????? |

|*? 2 |?? TABLE ACCESS FULL| TB_TEST? ?|???? 1 |???? 4 |???? 6?? (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------

?? 2 - filter("T"."ID"=1)

?

-- Oracle給出的運行計劃

2- Using SQL Profile
--------------------
Plan hash value: 847665939

--------------------------------------------------------------------------------
---
| Id? | Operation???????? | Name????????? | Rows? | Bytes | Cost (%CPU)| Time
? |

DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---
|?? 0 | SELECT STATEMENT? |?????????????? |???? 1 |???? 4 |???? 1?? (0)| 00:00:0
1 |
|?? 1 |? SORT AGGREGATE?? |?????????????? |???? 1 |???? 4 |??????????? |
? |
|*? 2 |?? INDEX RANGE SCAN| IDX_TB_TEST? ?|???? 1 |???? 4 |???? 1?? (0)| 00:00:0
1 |
--------------------------------------------------------------------------------
---


DBMS_SQLTUNE.REPORT_TUNING_TASK(‘TASK_NAME01‘)
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------

?? 2 - access("T"."ID"=1)

-------------------------------------------------------------------------------

從上面的輸出能夠看出Oracle給出的運行計劃是正確的.能夠使用例如以下方法使用正確的運行計劃

begin
? dbms_sqltune.accept_sql_profile(task_name => ‘task_name01‘, replace => TRUE);
end;

-- The End --




使用hint優化Oracle的運行計劃 以及 SQL Tune Advisor的使用