SQL Profiles-Part I--老熊

dawn009發表於2014-07-30

Oracle 11g從釋出到現在,也有幾個年頭了。而在國內來說,Oracle 10g仍然是主流,甚至一些電信運營商的核心繫統仍然在使用9i。作為Oracle 10g的一項新特性,SQL Profiles被使用得並不太多。不管是在論壇、個人的BLOG還是其他一些地方,SQL Profiles的介紹也相對較少。對我個人來說,已經在多個最佳化場合中使用SQL Profiles,在這裡向大家介紹SQL Profiles,就是希望能夠了解Oracle資料庫的這一功能。

SQL Profiles可以說是Outlines的進化。Outlines能夠實現的功能SQL Profiles也完全能夠實現,而SQL Profiles具有Outlines不具備的最佳化,個人認為最重要的有2點:

  • SQL Profiles更容易生成、更改和控制。
  • SQL Profiles在對SQL語句的支援上做得更好,也就是適用範圍更廣。

關於這2方面的優點,我後面會詳細地闡述。

現在我在使用Outlines的場合,均使用SQL Profiles來替代。有一次準備對1條SQL語句使用Outline進行執行計劃的穩定,結果使用Outline之後,系統出現大量的library cache latch的爭用,不得不關閉Outline的使用,但是改用SQL Profiles不再有這個問題。這或許是個BUG,不過既然能用SQL Profiles代替,也就沒再深入去研究這個問題。

使用SQL Profiles無非是兩個目的:

  • 鎖定或者說是穩定執行計劃。
  • 在不能修改應用中的SQL的情況下使SQL語句按指定的執行計劃執行。

那麼SQL Profile到底是什麼?在我看來,SQL Profile就是為某一SQL語句提供除了系統統計資訊、物件(表和索引等)統計資訊之外的其他資訊,比如執行環境、額外的更準確的統計資訊,以幫助最佳化器為SQL語句選擇更適合的執行計劃。這些說法顯得比較枯燥,還是來看看下面的測試。

首先建2個測試表:

  1. SQL> create table t1 as select object_id,object_name from dba_objects where rownum<=50000;  
  2.   
  3. 表已建立。  
  4.   
  5. SQL> create table t2 as select * from dba_objects;  
  6.   
  7. 表已建立。  
  8.   
  9. SQL> create index t2_idx on t2(object_id);  
  10.   
  11. 索引已建立。  
  12.   
  13. SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true,method_opt=>'for all columns size 1');  
  14.   
  15. PL/SQL 過程已成功完成。  
  16.   
  17. SQL> exec dbms_stats.gather_table_stats(user,'t2',cascade=>true,method_opt=>'for all columns size 1');  
  18.   
  19. PL/SQL 過程已成功完成。  

然後看看下面這一條SQL:

  1. SQL> select t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%' and t1.object_id=t2.object_id;  
  2.   
  3. 已選擇29行。  
  4.   
  5.   
  6. 執行計劃  
  7. ----------------------------------------------------------  
  8. Plan hash value: 1838229974  
  9.   
  10. ---------------------------------------------------------------------------  
  11. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  12. ---------------------------------------------------------------------------  
  13. |   0 | SELECT STATEMENT   |      |  2498 | 99920 |   219   (4)| 00:00:03 |  
  14. |*  1 |  HASH JOIN         |      |  2498 | 99920 |   219   (4)| 00:00:03 |  
  15. |*  2 |   TABLE ACCESS FULL| T1   |  2498 | 72442 |    59   (6)| 00:00:01 |  
  16. |   3 |   TABLE ACCESS FULL| T2   | 49954 |   536K|   159   (2)| 00:00:02 |  
  17. ---------------------------------------------------------------------------  
  18.   
  19. Predicate Information (identified by operation id):  
  20. ---------------------------------------------------  
  21.   
  22.    1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  
  23.    2 - filter("T1"."OBJECT_NAME" LIKE '%T1%')  
  24.   
  25.   
  26. 統計資訊  
  27. ----------------------------------------------------------  
  28.           0  recursive calls  
  29.           0  db block gets  
  30.         932  consistent gets  
  31.           0  physical reads  
  32.           0  redo size  
  33.        1352  bytes sent via SQL*Net to client  
  34.         385  bytes received via SQL*Net from client  
  35.           2  SQL*Net roundtrips to/from client  
  36.           0  sorts (memory)  
  37.           0  sorts (disk)  
  38.          29  rows processed  

這裡省略了SELECT出來的具體資料,但是我們關心的是返回的結果行數、執行計劃以及邏輯讀這些資訊。
首先從執行計劃可以看到,這條SQL語句在2個表上都是全表掃描。在第1個表T1上,有 like ‘%T1%’這樣的條件,導致只能全表掃描,這沒有問題。但是第2個表,也是全表掃描,這裡有沒有問題呢?或者說是有沒有最佳化的餘地,答案顯然是肯定的。
這裡的問題在於執行計劃ID=1的那一行,Oracle最佳化器評估T1 like ‘%T1%’返回的結果行數為2498行,即T1表總行數的5%,如果2個表採用index range scan+nested loop連線,oracle評估的成本會高於full table scan+hash join。下面可以看到Oracle最佳化器評估的index range_scan+nested loop的成本:

  1. SQL> explain plan for select /*+ use_nl(t1 t2) index(t2) */ t1.*,t2.owner   
  2.      from t1,t2   
  3.      where t1.object_name like '%T1%'   
  4.      and t1.object_id=t2.object_id;  
  5.   
  6. 已解釋。  
  7.   
  8. SQL> @showplan  
  9.   
  10. PLAN_TABLE_OUTPUT  
  11. --------------------------------------------------------------------------------------  
  12. Plan hash value: 3787413387  
  13. --------------------------------------------------------------------------------------  
  14. | Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |  
  15. --------------------------------------------------------------------------------------  
  16. |   0 | SELECT STATEMENT            |        |  2498 | 99920 |  5061   (1)| 00:01:01 |  
  17. |   1 |  TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |  
  18. |   2 |   NESTED LOOPS              |        |  2498 | 99920 |  5061   (1)| 00:01:01 |  
  19. |*  3 |    TABLE ACCESS FULL        | T1     |  2498 | 72442 |    59   (6)| 00:00:01 |  
  20. |*  4 |    INDEX RANGE SCAN         | T2_IDX |     1 |       |     1   (0)| 00:00:01 |  
  21. --------------------------------------------------------------------------------------  
  22. Predicate Information (identified by operation id):  
  23. ---------------------------------------------------  
  24.    3 - filter("T1"."OBJECT_NAME" LIKE '%T1%')  
  25.    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  

從執行計劃可以看到Oracle最佳化器評估的成本為5061,遠遠高於原來的219。
但是實際的邏輯讀是多少呢?

  1. 統計資訊  
  2. ----------------------------------------------------------  
  3.           0  recursive calls  
  4.           0  db block gets  
  5.         290  consistent gets  
  6.           0  physical reads  
  7.           0  redo size  
  8.        1352  bytes sent via SQL*Net to client  
  9.         385  bytes received via SQL*Net from client  
  10.           2  SQL*Net roundtrips to/from client  
  11.           0  sorts (memory)  
  12.           0  sorts (disk)  
  13.          29  rows processed  

加了HINT之後實際的邏輯讀只有290,低於原始SQL的932。所以這裡可以看出來,由於Oracle最佳化器過高地估計了T1表經過like操作過濾返回的行數,也就過高地估計了nest loop的成本,最終也就選擇了不是最優的執行計劃。

下面我們用Oracle的SQL Tuning Advisor來嘗試這條SQL:

  1. SQL> var tuning_task varchar2(100);  
  2. SQL> DECLARE  
  3.   2    l_sql_id v$session.prev_sql_id%TYPE;  
  4.   3    l_tuning_task VARCHAR2(30);  
  5.   4  BEGIN  
  6.   5    l_sql_id:='4zbqykx89yc8v';  
  7.   6    l_tuning_task := dbms_sqltune.create_tuning_task(sql_id => l_sql_id);  
  8.   7    :tuning_task:=l_tuning_task;  
  9.   8    dbms_sqltune.execute_tuning_task(l_tuning_task);  
  10.   9    dbms_output.put_line(l_tuning_task);  
  11.  10  END;  
  12.  11  /  
  13. 任務_74  
  14.   
  15. PL/SQL 過程已成功完成。  
  16.   
  17. SQL> print tuning_task;  
  18.   
  19. TUNING_TASK  
  20. ---------------------------------------------------------------------------------------------------------  
  21. 任務_74  
  22.   
  23. SQL> SELECT dbms_sqltune.report_tuning_task(:tuning_task) FROM dual;  
  24.   
  25. DBMS_SQLTUNE.REPORT_TUNING_TASK(:TUNING_TASK)  
  26. --------------------------------------------------------------------------------  
  27. GENERAL INFORMATION SECTION  
  28. -------------------------------------------------------------------------------  
  29. Tuning Task Name                  : 任務_74  
  30. Tuning Task Owner                 : TEST1  
  31. Scope                             : COMPREHENSIVE  
  32. Time Limit(seconds)               : 1800  
  33. Completion Status                 : COMPLETED  
  34. Started at                        : 12/15/2010 09:56:02  
  35. Completed at                      : 12/15/2010 09:56:03  
  36. Number of SQL Profile Findings    : 1  
  37.   
  38. -------------------------------------------------------------------------------  
  39. Schema Name: TEST1  
  40. SQL ID     : 4zbqykx89yc8v  
  41. SQL Text   : select t1.*,t2.owner from t1,t2 where t1.object_name like '%T1%'  
  42.              and t1.object_id=t2.object_id  
  43.   
  44. -------------------------------------------------------------------------------  
  45. FINDINGS SECTION (1 finding)  
  46. -------------------------------------------------------------------------------  
  47.   
  48. 1- SQL Profile Finding (see explain plans section below)  
  49. --------------------------------------------------------  
  50.  為此語句找到了效能  
  51.   
  52.   Recommendation (estimated benefit: 46.62%)  
  53.   ------------------------------------------  
  54.   -考慮接受推薦的 SQL  
  55.     executedbms_sqltune.accept_sql_profile(task_name => '任務_74'replace =  
  56.             TRUE);  
  57.   
  58. -------------------------------------------------------------------------------  
  59. EXPLAIN PLANS SECTION  
  60. -------------------------------------------------------------------------------  
  61.   
  62. 1- Original With Adjusted Cost  
  63. ------------------------------  
  64. Plan hash value: 1838229974  
  65.   
  66. ---------------------------------------------------------------------------  
  67. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  68. ---------------------------------------------------------------------------  
  69. |   0 | SELECT STATEMENT   |      |    29 |  1160 |   219   (4)| 00:00:03 |  
  70. |*  1 |  HASH JOIN         |      |    29 |  1160 |   219   (4)| 00:00:03 |  
  71. |*  2 |   TABLE ACCESS FULL| T1   |    29 |   841 |    59   (6)| 00:00:01 |  
  72. |   3 |   TABLE ACCESS FULL| T2   | 49954 |   536K|   159   (2)| 00:00:02 |  
  73. ---------------------------------------------------------------------------  
  74.   
  75. Predicate Information (identified by operation id):  
  76. ---------------------------------------------------  
  77.   
  78.    1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  
  79.    2 - filter("T1"."OBJECT_NAME" LIKE '%T1%')  
  80.   
  81. 2- Using SQL Profile  
  82. --------------------  
  83. Plan hash value: 3787413387  
  84.   
  85. --------------------------------------------------------------------------------------  
  86. | Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |  
  87. --------------------------------------------------------------------------------------  
  88. |   0 | SELECT STATEMENT            |        |    29 |  1160 |   117   (3)| 00:00:02 |  
  89. |   1 |  TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |  
  90. |   2 |   NESTED LOOPS              |        |    29 |  1160 |   117   (3)| 00:00:02  
  91.  |  
  92. |*  3 |    TABLE ACCESS FULL        | T1     |    29 |   841 |    59   (6)| 00:00:01 |  
  93. |*  4 |    INDEX RANGE SCAN         | T2_IDX |     1 |       |     1   (0)| 00:00:01 |  
  94. --------------------------------------------------------------------------------------  
  95.   
  96. Predicate Information (identified by operation id):  
  97. ---------------------------------------------------  
  98.   
  99.    3 - filter("T1"."OBJECT_NAME" LIKE '%T1%')  
  100.    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  
  101.   
  102. -------------------------------------------------------------------------------  


上面程式碼中的sql_id是從v$sql來,對應的是沒有加hint的SQL。
結果看起來非常棒,SQL Tuning Advisor為我們找到了理想的執行計劃,T1表上經過謂詞過濾後返回的行數評估為29,相當地精確。我們要做的就是Accept SQL Profile,接受這個SQL Profile。

  1. SQL> execute dbms_sqltune.accept_sql_profile(task_name => :tuning_task,replace => TRUE,force_match=>true);  
  2.   
  3. PL/SQL 過程已成功完成。  

那麼我們再執行其他的類似SQL看看:

  1. SQL> select t1.*,t2.owner from t1,t2 where t1.object_name like '%T2%' and t1.object_id=t2.object_id;  
  2.   
  3. 已選擇77行。  
  4.   
  5. 執行計劃  
  6. ----------------------------------------------------------  
  7. Plan hash value: 3787413387  
  8. --------------------------------------------------------------------------------------  
  9. | Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |  
  10. --------------------------------------------------------------------------------------  
  11. |   0 | SELECT STATEMENT            |        |    29 |  1160 |   117   (3)| 00:00:02 |  
  12. |   1 |  TABLE ACCESS BY INDEX ROWID| T2     |     1 |    11 |     2   (0)| 00:00:01 |  
  13. |   2 |   NESTED LOOPS              |        |    29 |  1160 |   117   (3)| 00:00:02 |  
  14. |*  3 |    TABLE ACCESS FULL        | T1     |    29 |   841 |    59   (6)| 00:00:01 |  
  15. |*  4 |    INDEX RANGE SCAN         | T2_IDX |     1 |       |     1   (0)| 00:00:01 |  
  16. --------------------------------------------------------------------------------------  
  17. Predicate Information (identified by operation id):  
  18. ---------------------------------------------------  
  19.    3 - filter("T1"."OBJECT_NAME" LIKE '%T2%')  
  20.    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  
  21. Note  
  22. -----  
  23.    - SQL profile "SYS_SQLPROF_014b39f084c88000" used for this statement  
  24.   
  25. 統計資訊  
  26. ----------------------------------------------------------  
  27.           1  recursive calls  
  28.           0  db block gets  
  29.         343  consistent gets  
  30.           0  physical reads  
  31.           0  redo size  
  32.        2840  bytes sent via SQL*Net to client  
  33.         385  bytes received via SQL*Net from client  
  34.           2  SQL*Net roundtrips to/from client  
  35.           0  sorts (memory)  
  36.           0  sorts (disk)  
  37.          77  rows processed  

這一次,儘管我們更改了LIKE 後面的值,但是執行計劃與SQL Tuning Advisor產生的執行計劃完全一樣。從執行計劃的”Note“一節也可以看到,SQL Profile起作用了。SQL Profile的名字為”SYS_SQLPROF_014b39f084c88000″。

  1. SQL> select name,category,signature,type,status,force_matching from dba_sql_profiles;  
  2.   
  3. NAME                           CATEGORY                                   SIGNATURE TYPE      STATUS  FOR  
  4. ------------------------------ ------------------------------ --------------------- --------- ---------- ---  
  5. SYS_SQLPROF_014b39f084c88000   DEFAULT                          3960696072677096522 MANUAL    ENABLED    YES  

一些複雜的SQL,我經常會先透過SQL Tuning Advisor來分析一下,看能不能讓Oracle自已找出一個更好的執行計劃。

我們來看看,SQL Profiles實際上是些什麼:

  1. SQLselect * from sys.sqlprof$attr;  
  2.   
  3.             SIGNATURE CATEGORY                            ATTR# ATTR_VAL  
  4. --------------------- ------------------------------ ---------- ----------------------------------------  
  5.   3960696072677096522 DEFAULT                                 1 OPT_ESTIMATE(@"SEL$1"TABLE"T1"@"SEL$ 
  6.                                                                 1", SCALE_ROWS=0.01161091426)  

從sys.sqlprof$attr這個數字字典裡面,我們可以看到兩樣東西:signature和attr。
signature是什麼?可以理解為與sql_id、sql_hash_value類似的值,用來標識SQL。在10g以上的版本中,檢視v$sql的定義就可以發現2列:exact_matching_signature、force_matching_signature。透過下面的資料可以看出區別:

  1. SQL> select rownum,a.* from   
  2.   (select exact_matching_signature,force_matching_signature,plan_hash_value,sql_text   
  3.   from v$sql where sql_text like '%/*%xjs%' and sql_text not like '%v$sql%' order by 1) a;  
  4.   
  5.     ROWNUM EXACT_MATCHING_SIGNATURE FORCE_MATCHING_SIGNATURE PLAN_HASH_VALUE SQL_TEXT  
  6. ---------- ------------------------ ------------------------ --------------- --------------------------------------------------  
  7.          1      3939730931515200254     17443893418101517951      3617692013 select /* xjs */ object_name    from T1 where obje  
  8.                                                                              ct_name='t1'  
  9.   
  10.          2     10964210455693560558     11097449316038436385      3836375644 select /* xjs */ object_name    from T1 where rown  
  11.                                                                              um<=3  
  12.   
  13.          3     10964210455693560558     11097449316038436385      3836375644 select /* xjs   */ object_name    from T1 where ro  
  14.                                                                              wnum<=3  
  15.   
  16.          4     11217690300719901571       354482119692997204      3836375644 select /* xjs */ 2 from t1 where rownum<=1  
  17.          5     11974975582747367847       354482119692997204      3836375644 select /* xjs */ 1 from t1 where rownum<=1  
  18.          6     12941882703651921406     17443893418101517951      3617692013 select /* xjs */ object_name    from T1 where obje  
  19.                                                                              ct_name='T1'  
  20.   
  21.          7     17986178357953662359     11097449316038436385      3836375644 select /* xjs */ object_name    from T1 where rown  
  22.                                                                              um<=1  
  23.   
  24.          8     17986178357953662359     11097449316038436385      3836375644 select /* xjs */ OBJECT_NAME from T1 where rownum
  25.                                                                              =1  
  26.   
  27.          9     17986178357953662359     11097449316038436385      3836375644 SELECT /* xjs */ object_name    from T1 where rown  
  28.                                                                              um<=1  
  29.   
  30.         10     17986178357953662359     11097449316038436385      3836375644 select /* xjs */ object_name from t1 where rownum
  31.                                                                              =1  

從上面的資料可以看出:

  • 第2、3條SQL的exact_matching_signature相同,第7、8、9、10條SQL的exact_matching_signature相同。
  • 第2、3條SQL的force_matching_signature相同,第4、5條SQL的force_matching_signature相同,第7、8、9、10條的SQL的force_matching_signature相同。第1、6條SQL的force_matching_signature相同

有如下的結論:對SQL語句,去掉重複的空格(不包括字元常量),將大小寫轉換成相同,比如均為大寫(不包括字元常量)後,如果SQL相同,那麼SQL語句的exact_matching_signature就是相同的。對SQL語句,去掉重複的空格(不包括字元常量),將大小寫轉換成相同,比如均為大寫(不包括字元常量),然後去掉SQL中的常量,如果SQL相同,那麼SQL語句的force_matching_signature就是相同的。但是例外的情況是:如果SQL中有繫結變數,force_matching_signature就會與exact_matching_signature一樣的生成標準。

  1. SQL> select rownum,a.* from   
  2. (select exact_matching_signature,force_matching_signature,plan_hash_value,sql_text   
  3. from v$sql where sql_text like '%/*%xjs2%' and sql_text not like '%v$sql%' order by 1) a;  
  4.   
  5.     ROWNUM EXACT_MATCHING_SIGNATURE FORCE_MATCHING_SIGNATURE PLAN_HASH_VALUE SQL_TEXT  
  6. ---------- ------------------------ ------------------------ --------------- --------------------------------------------------  
  7.          1      5363536431331905229      5363536431331905229      3836375644 select /* xjs2 */ object_name    from T1 where obj  
  8.                                                                              ect_name='T1' and rownum<=:rn  
  9.   
  10.          2      5363536431331905229      5363536431331905229      3836375644 select /* xjs2 */ object_name    from t1 where obj  
  11.                                                                              ect_name='T1' and rownum<=:rn  
  12.   
  13.          3     12992689086515482106     12992689086515482106      3836375644 select /* xjs2 */ object_name    from t1 where obj  
  14.                                                                              ect_name='T2' and rownum<=:rn  

可以看到,現在exact_matching_signature與force_matching_signature完全一樣了。
從force_matching_signature的特性,我們可以想到一個用途,用於查詢沒有使用繫結變數的SQL語句,類似於使用plan_hash_value來查詢。

回到前面,accept_sql_profile這個過程,force_match引數設為TRUE,那麼dba_sql_profiles中的signature則是由SQL的force_matching_signature而來,否則便是exact_matching_signature。對於Outlines來說,則只能是exact_matching_signature。從這個角度上講,Sql Profiles比Outlines的使用範圍更廣,因為Sql profiles對沒有使用繫結變數的SQL也支援得很好。值得注意的是,Sql profiles的force_match屬性是不能更改的,只能在建立時指定,如果要更改,則只能重新建立改Sql Profile。

下面來看看sys.sqlprof$attr資料字典。這裡面沒有SQL Profile的名字,而是用的sql的signature。大家從attr_val的結果發現了什麼?

  1. OPT_ESTIMATE(@"SEL$1"TABLE"T1"@"SEL$1", SCALE_ROWS=0.01161091426)  

可以看到,SQL Profiles的attr_val實際上就是一些Hints,這跟Outlines沒有本質上的區別。只是SQL Profiles中的Hint,沒有指定SQL使用哪個索引,也沒有指定表的連線方法和連線順序。這裡只指定了T1表評估返回的行數,與原始的評估返回的行數的放大縮小的倍數。2498*0.01161091426正好為29。這裡就是告訴Oracle最佳化器,T1表經過謂語過濾後返回行數應該為評估的0.01161091426倍。從這裡可以看出,SQL Profiles並不會鎖定SQL的執行計劃,只是提供了更多、更準確的統計資訊給最佳化器。看下面的測試:

  1. SQL> exec dbms_stats.set_table_stats('TEST1','T1',numrows=>5000000);  
  2.   
  3. PL/SQL 過程已成功完成。  
  4. SQL> explain plan for select  t1.*,t2.owner  
  5.   2       from t1,t2  
  6.   3       where t1.object_name like '%T1%'  
  7.   4       and t1.object_id=t2.object_id;  
  8.   
  9. 已解釋。  
  10.   
  11. SQL> @showplan  
  12.   
  13. PLAN_TABLE_OUTPUT  
  14. ----------------------------------------------------------------------------------  
  15. Plan hash value: 1838229974  
  16. ---------------------------------------------------------------------------  
  17. | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  18. ---------------------------------------------------------------------------  
  19. |   0 | SELECT STATEMENT   |      |  2903 |   113K|   448  (53)| 00:00:06 |  
  20. |*  1 |  HASH JOIN         |      |  2903 |   113K|   448  (53)| 00:00:06 |  
  21. |*  2 |   TABLE ACCESS FULL| T1   |  2903 | 84187 |   288  (81)| 00:00:04 |  
  22. |   3 |   TABLE ACCESS FULL| T2   | 49954 |   536K|   159   (2)| 00:00:02 |  
  23. ---------------------------------------------------------------------------  
  24. Predicate Information (identified by operation id):  
  25. ---------------------------------------------------  
  26.    1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID")  
  27.    2 - filter("T1"."OBJECT_NAME" LIKE '%T1%')  
  28. Note  
  29. -----  
  30.    - SQL profile "SYS_SQLPROF_014b39f084c88000" used for this statement  

將T1表的統計資訊中的錶行數改為500萬,Oracle就會評估為返回5000000*5%*0.01161091426=2903行。這裡執行計劃又變回為full scan+hash join。可以看到,雖然SQL Profile起作用了,但是並沒有鎖定執行計劃。

小結:本文簡單介紹了什麼是SQL Profiles及其作用,如何使用SQL Tuning Advisor來生成SQL Profile,以及生成的SQL Profile產生的Hint。同時也介紹了SQL的signature。

下一篇將會介紹如何手工來為建立、生成SQL Profile,以及如何讓SQL Profile也能像Outlines一樣鎖定SQL的執行計劃,以保持SQL執行計劃的穩定性。

--&gt>轉載於:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29119536/viewspace-1242415/,如需轉載,請註明出處,否則將追究法律責任。

相關文章