2011-10-23 49 views
0

我有一個表「討論」,它的結構如下:Oracle查詢性能問題

表名:討論,

Id  name  parent_id root_id ...other columns 
1 discussion1  0   0 
2 discussion2  1   1 
3 discussion3  2   1 
4 discussion4  3   1 
5 discussion5  4   1 

顯然ID被定義爲PK,PARENT_ID和root_id已被索引。

這些表的行被構建爲一個層次關係(父 - >子),以及請注意列root_id用於描述這些行在同一棵樹。

我寫了兩個SQLS獲得線程樹:

SQL 1

SELECT * 
    from discussion 
    start with (parent_Id=0 AND id=?) 
connect by prior Id=parent_Id 

SQL 2

SELECT * FROM (
      SELECT * FROM discussion WHERE root_id = ? or id = ? 
     )START WITH (parent_Id=0 AND id=?) connect by prior Id=parent_Id 

經過我的測試,如果數據集左右4000,SQL 1比SQL2做得好一點。 但是,如果表討論的數據量非常大,那麼SQL 2比SQL1做得好得多。

當表中有30萬行時,查詢計劃報告的SQL 1的成本是22126,SQL 2的成本是6 SQL 1涉及全表掃描或SQL 2獲取範圍索引掃描。

有人可以幫我解釋爲什麼兩個SQL顯示不同的結果與不同的數據編號集?

更重要的是我想讓你們的建議改善性能或其他解決方案?

這是當我們有30萬行時,查詢計劃SQL 1

GENERAL INFORMATION SECTION 
------------------------------------------------------------------------------- 
Tuning Task Name : staName52149 
Tuning Task Owner : CISCO 
Tuning Task ID  : 54 
Workload Type  : Single SQL Statement 
Execution Count : 1 
Current Execution : EXEC_44 
Execution Type  : TUNE SQL 
Scope    : COMPREHENSIVE 
Time Limit(seconds): 1800 
Completion Status : COMPLETED 
Started at   : 10/23/2011 23:23:31 
Completed at  : 10/23/2011 23:23:59 

------------------------------------------------------------------------------- 
Schema Name: CISCO 
SQL ID  : davhv6p4x6bu2 
SQL Text : SELECT * from discussion start with (parent_Id=0 AND id=6587) 
      connect by prior Id=parent_Id 

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

1- SQL Profile Finding (see explain plans section below) 
-------------------------------------------------------- 
    A potentially better execution plan was found for this statement. 

    Recommendation (estimated benefit: 99.99%) 
    ------------------------------------------ 
    - Consider accepting the recommended SQL profile. 
    execute dbms_sqltune.accept_sql_profile(task_name => 'staName52149', 
      task_owner => 'CISCO', replace => TRUE); 

    Validation results 
    ------------------ 
    The SQL profile was tested by executing both its plan and the original plan 
    and measuring their respective execution statistics. A plan may have been 
    only partially executed if the other could be run to completion in less time. 

          Original Plan With SQL Profile % Improved 
          ------------- ---------------- ---------- 
    Completion Status:   COMPLETE   COMPLETE 
    Elapsed Time(us):   14251990    121  99.99 % 
    CPU Time(us):     3463222     0  100 % 
    User I/O Time(us):   10821745     0  100 % 
    Buffer Gets:     678361     6  99.99 % 
    Physical Read Requests:   1013     0  100 % 
    Physical Write Requests:   1081     0  100 % 
    Physical Read Bytes:  234168320     0  100 % 
    Physical Write Bytes:  223756288     0  100 % 
    Rows Processed:      1     1 
    Fetches:       1     1 
    Executions:       1     1 

    Notes 
    ----- 
    1. The SQL profile plan was first executed to warm the buffer cache. 
    2. Statistics for the SQL profile plan were averaged over next 9 executions. 

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

1- Original 
----------- 
Plan hash value: 2811036397 


------------------------------------------------------------------------------------------------------ 
| Id | Operation        | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT      |   | 348K| 2770M| 22162 (82)| 00:04:26 | 
|* 1 | CONNECT BY NO FILTERING WITH START-WITH|   |  |  |   |   | 
| 2 | TABLE ACCESS FULL      | DISCUSSION | 348K| 79M| 4108 (1)| 00:00:50 | 
------------------------------------------------------------------------------------------------------ 

Query Block Name/Object Alias (identified by operation id): 
------------------------------------------------------------- 

    1 - SEL$1 
    2 - SEL$2/[email protected]$2 

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

    1 - access("DISCUSSION"."PARENT_ID"=PRIOR NULL) 
     filter("PARENT_ID"=0 AND "ID"=6587) 

Column Projection Information (identified by operation id): 
----------------------------------------------------------- 

    1 - "DISCUSSION"."PARENT_ID"[NUMBER,22], "DISCUSSION"."ID"[NUMBER,22], STRDEF[22], 
     STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[4000], STRDEF[22], STRDEF[22], 
     STRDEF[150], STRDEF[7], STRDEF[7], STRDEF[4000], STRDEF[22], STRDEF[22], STRDEF[22], 
     STRDEF[4000], STRDEF[22], STRDEF[4000], STRDEF[7], STRDEF[22], STRDEF[32], STRDEF[22], 
     STRDEF[22], STRDEF[22], STRDEF[7], STRDEF[7], PRIOR NULL[22], LEVEL[4] 
    2 - "ID"[NUMBER,22], "DISCUSSION"."CLASS"[NUMBER,22], "DISCUSSION"."SUBCLASS"[NUMBER,22], 
     "PARENT_ID"[NUMBER,22], "DISCUSSION"."ROOT_ID"[NUMBER,22], 
     "DISCUSSION"."MESSAGE"[VARCHAR2,4000], "DISCUSSION"."STATUS"[NUMBER,22], 
     "DISCUSSION"."PRIORITY"[NUMBER,22], "DISCUSSION"."AUTO_NUMBER"[VARCHAR2,150], 
     "DISCUSSION"."CREATE_DATE"[DATE,7], "DISCUSSION"."CLOSE_DATE"[DATE,7], 
     "DISCUSSION"."CLOSE_COMMENTS"[VARCHAR2,4000], "DISCUSSION"."ORGANIZATION"[NUMBER,22], 
     "DISCUSSION"."TYPE"[NUMBER,22], "DISCUSSION"."CREATOR"[NUMBER,22], 
     "DISCUSSION"."SUBJECT"[VARCHAR2,4000], "DISCUSSION"."REPLIES"[NUMBER,22], 
     "DISCUSSION"."NOTIFYLIST"[VARCHAR2,4000], "DISCUSSION"."LAST_REPLY_DATE"[DATE,7], 
     "DISCUSSION"."DELETE_FLAG"[NUMBER,22], "DISCUSSION"."FLAGS"[VARCHAR2,32], 
     "DISCUSSION"."PREVIEW_TEXT"[NUMBER,22], "DISCUSSION"."FILTER"[NUMBER,22], 
     "DISCUSSION"."OBJVERSION"[NUMBER,22], "DISCUSSION"."CREATED"[DATE,7], 
     "DISCUSSION"."LAST_UPD"[DATE,7] 

2- Original With Adjusted Cost 
------------------------------ 
Plan hash value: 2811036397 


------------------------------------------------------------------------------------------------------ 
| Id | Operation        | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------------------------------ 
| 0 | SELECT STATEMENT      |   | 348K| 2770M| 22162 (82)| 00:04:26 | 
|* 1 | CONNECT BY NO FILTERING WITH START-WITH|   |  |  |   |   | 
| 2 | TABLE ACCESS FULL      | DISCUSSION | 348K| 79M| 4108 (1)| 00:00:50 | 
------------------------------------------------------------------------------------------------------ 

Query Block Name/Object Alias (identified by operation id): 
------------------------------------------------------------- 

    1 - SEL$1 
    2 - SEL$2/[email protected]$2 

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

    1 - access("DISCUSSION"."PARENT_ID"=PRIOR NULL) 
     filter("PARENT_ID"=0 AND "ID"=6587) 

Column Projection Information (identified by operation id): 
----------------------------------------------------------- 

    1 - "DISCUSSION"."PARENT_ID"[NUMBER,22], "DISCUSSION"."ID"[NUMBER,22], STRDEF[22], 
     STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[4000], STRDEF[22], STRDEF[22], 
     STRDEF[150], STRDEF[7], STRDEF[7], STRDEF[4000], STRDEF[22], STRDEF[22], STRDEF[22], 
     STRDEF[4000], STRDEF[22], STRDEF[4000], STRDEF[7], STRDEF[22], STRDEF[32], STRDEF[22], 
     STRDEF[22], STRDEF[22], STRDEF[7], STRDEF[7], PRIOR NULL[22], LEVEL[4] 
    2 - "ID"[NUMBER,22], "DISCUSSION"."CLASS"[NUMBER,22], "DISCUSSION"."SUBCLASS"[NUMBER,22], 
     "PARENT_ID"[NUMBER,22], "DISCUSSION"."ROOT_ID"[NUMBER,22], 
     "DISCUSSION"."MESSAGE"[VARCHAR2,4000], "DISCUSSION"."STATUS"[NUMBER,22], 
     "DISCUSSION"."PRIORITY"[NUMBER,22], "DISCUSSION"."AUTO_NUMBER"[VARCHAR2,150], 
     "DISCUSSION"."CREATE_DATE"[DATE,7], "DISCUSSION"."CLOSE_DATE"[DATE,7], 
     "DISCUSSION"."CLOSE_COMMENTS"[VARCHAR2,4000], "DISCUSSION"."ORGANIZATION"[NUMBER,22], 
     "DISCUSSION"."TYPE"[NUMBER,22], "DISCUSSION"."CREATOR"[NUMBER,22], 
     "DISCUSSION"."SUBJECT"[VARCHAR2,4000], "DISCUSSION"."REPLIES"[NUMBER,22], 
     "DISCUSSION"."NOTIFYLIST"[VARCHAR2,4000], "DISCUSSION"."LAST_REPLY_DATE"[DATE,7], 
     "DISCUSSION"."DELETE_FLAG"[NUMBER,22], "DISCUSSION"."FLAGS"[VARCHAR2,32], 
     "DISCUSSION"."PREVIEW_TEXT"[NUMBER,22], "DISCUSSION"."FILTER"[NUMBER,22], 
     "DISCUSSION"."OBJVERSION"[NUMBER,22], "DISCUSSION"."CREATED"[DATE,7], 
     "DISCUSSION"."LAST_UPD"[DATE,7] 

3- Using SQL Profile 
-------------------- 
Plan hash value: 3458076016 


--------------------------------------------------------------------------------------------------- 
| Id | Operation      | Name    | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |     |  2 | 16686 | 11 (28)| 00:00:01 | 
|* 1 | CONNECT BY WITH FILTERING |     |  |  |   |   | 
|* 2 | TABLE ACCESS BY INDEX ROWID | DISCUSSION  |  1 | 240 |  3 (0)| 00:00:01 | 
|* 3 | INDEX UNIQUE SCAN   | DISCUSSION_PK  |  1 |  |  2 (0)| 00:00:01 | 
| 4 | NESTED LOOPS    |     |  1 | 253 |  5 (0)| 00:00:01 | 
| 5 | CONNECT BY PUMP   |     |  |  |   |   | 
| 6 | TABLE ACCESS BY INDEX ROWID| DISCUSSION  |  1 | 240 |  3 (0)| 00:00:01 | 
|* 7 |  INDEX RANGE SCAN   | DISC_IDX_PARENTID |  1 |  |  2 (0)| 00:00:01 | 
--------------------------------------------------------------------------------------------------- 

Query Block Name/Object Alias (identified by operation id): 
------------------------------------------------------------- 

    1 - SEL$1 
    2 - SEL$4/[email protected]$4 
    3 - SEL$4/[email protected]$4 
    4 - SEL$3 
    6 - SEL$3/[email protected]$3 
    7 - SEL$3/[email protected]$3 

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

    1 - access("DISCUSSION"."PARENT_ID"=PRIOR NULL) 
    2 - filter("PARENT_ID"=0) 
    3 - access("ID"=6587) 
    7 - access("connect$_by$_pump$_002"."prior Id"="PARENT_ID") 

這裏是查詢計劃SQL 2時,我們有30萬行。

GENERAL INFORMATION SECTION 
------------------------------------------------------------------------------- 
Tuning Task Name : staName64031 
Tuning Task Owner : CISCO 
Tuning Task ID  : 55 
Workload Type  : Single SQL Statement 
Execution Count : 1 
Current Execution : EXEC_45 
Execution Type  : TUNE SQL 
Scope    : COMPREHENSIVE 
Time Limit(seconds): 1800 
Completion Status : COMPLETED 
Started at   : 10/23/2011 23:30:22 
Completed at  : 10/23/2011 23:30:26 

------------------------------------------------------------------------------- 
Schema Name: CISCO 
SQL ID  : c741jfryv5m98 
SQL Text : SELECT * FROM (
          SELECT * FROM discussion WHERE root_id = 6587 or 
      id = 6587 
          )Start With (Parent_Id=0 And Id=6587) Connect By 
      Prior Id=Parent_Id 

------------------------------------------------------------------------------- 
There are no recommendations to improve the statement. 

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

1- Original 
----------- 
Plan hash value: 1202872009 


----------------------------------------------------------------------------------------------------------- 
| Id | Operation        | Name   | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT      |     |  2 | 16686 |  6 (17)| 00:00:01 | 
|* 1 | CONNECT BY NO FILTERING WITH START-WITH|     |  |  |   |   | 
| 2 | TABLE ACCESS BY INDEX ROWID   | DISCUSSION  |  2 | 480 |  5 (0)| 00:00:01 | 
| 3 | BITMAP CONVERSION TO ROWIDS   |     |  |  |   |   | 
| 4 |  BITMAP OR       |     |  |  |   |   | 
| 5 |  BITMAP CONVERSION FROM ROWIDS  |     |  |  |   |   | 
|* 6 |  INDEX RANGE SCAN     | DISCUSSION_PK |  |  |  2 (0)| 00:00:01 | 
| 7 |  BITMAP CONVERSION FROM ROWIDS  |     |  |  |   |   | 
|* 8 |  INDEX RANGE SCAN     | DISC_IDX_ROOTID |  |  |  3 (0)| 00:00:01 | 
----------------------------------------------------------------------------------------------------------- 

Query Block Name/Object Alias (identified by operation id): 
------------------------------------------------------------- 

    1 - SEL$1  
    2 - SEL$E029B2FF/[email protected]$5 

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

    1 - access("DISCUSSION"."PARENT_ID"=PRIOR NULL) 
     filter("DISCUSSION"."PARENT_ID"=0 AND "DISCUSSION"."ID"=6587) 
    6 - access("ID"=6587) 
    8 - access("ROOT_ID"=6587) 

Column Projection Information (identified by operation id): 
----------------------------------------------------------- 

    1 - "DISCUSSION"."PARENT_ID"[NUMBER,22], "DISCUSSION"."ID"[NUMBER,22], STRDEF[22], STRDEF[22], 
     STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[4000], STRDEF[22], STRDEF[22], STRDEF[150], STRDEF[7], 
     STRDEF[7], STRDEF[4000], STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[4000], STRDEF[22], 
     STRDEF[4000], STRDEF[7], STRDEF[22], STRDEF[32], STRDEF[22], STRDEF[22], STRDEF[22], STRDEF[7], 
     STRDEF[7], PRIOR NULL[22], LEVEL[4] 
    2 - "DISCUSSION".ROWID[ROWID,10], "ID"[NUMBER,22], "DISCUSSION"."CLASS"[NUMBER,22], 
     "DISCUSSION"."SUBCLASS"[NUMBER,22], "DISCUSSION"."PARENT_ID"[NUMBER,22], "ROOT_ID"[NUMBER,22], 
     "DISCUSSION"."MESSAGE"[VARCHAR2,4000], "DISCUSSION"."STATUS"[NUMBER,22], 
     "DISCUSSION"."PRIORITY"[NUMBER,22], "DISCUSSION"."AUTO_NUMBER"[VARCHAR2,150], 
     "DISCUSSION"."CREATE_DATE"[DATE,7], "DISCUSSION"."CLOSE_DATE"[DATE,7], 
     "DISCUSSION"."CLOSE_COMMENTS"[VARCHAR2,4000], "DISCUSSION"."ORGANIZATION"[NUMBER,22], 
     "DISCUSSION"."TYPE"[NUMBER,22], "DISCUSSION"."CREATOR"[NUMBER,22], 
     "DISCUSSION"."SUBJECT"[VARCHAR2,4000], "DISCUSSION"."REPLIES"[NUMBER,22], 
     "DISCUSSION"."NOTIFYLIST"[VARCHAR2,4000], "DISCUSSION"."LAST_REPLY_DATE"[DATE,7], 
     "DISCUSSION"."DELETE_FLAG"[NUMBER,22], "DISCUSSION"."FLAGS"[VARCHAR2,32], 
     "DISCUSSION"."PREVIEW_TEXT"[NUMBER,22], "DISCUSSION"."FILTER"[NUMBER,22], 
     "DISCUSSION"."OBJVERSION"[NUMBER,22], "DISCUSSION"."CREATED"[DATE,7], 
     "DISCUSSION"."LAST_UPD"[DATE,7] 
    3 - "DISCUSSION".ROWID[ROWID,10] 
    4 - STRDEF[BM VAR, 10], STRDEF[BM VAR, 10], STRDEF[BM VAR, 16116] 
    5 - STRDEF[BM VAR, 10], STRDEF[BM VAR, 10], STRDEF[BM VAR, 16116] 
    6 - "DISCUSSION".ROWID[ROWID,10] 
    7 - STRDEF[BM VAR, 10], STRDEF[BM VAR, 10], STRDEF[BM VAR, 16116] 
    8 - "DISCUSSION".ROWID[ROWID,10] 

------------------------------------------------------------------------------- 
+0

對不起,它與同一張表一起工作,在sql –

回答

1

你只是想解釋一下你所看到的內容嗎?或建議改善呢?

假設第一:

隨着SQL1數據庫必須找到根元素,那麼所有的孩子,那麼那等孩子。由於沒有可用的通用過濾器,它總是需要使用完整的表格。它處理整個表格(或完整索引)。

對於SQL2,數據庫系統可以做的第一件事就是減少正在處理的行的子集。

小桌子的差異很小(甚至在相反的方向)。如果你的桌子適合一到兩塊,那麼數據庫可以做的並不是很有用的過濾。無論如何,它必須將這些塊放入內存中。更多,如果它使用索引訪問。但是對於一個巨大的表格(只是編制數字)而言,將這些數字減少到5個的100個塊首先是諮詢2個索引塊,這是巨大的收益。

更新:一些想法,以調整此:

  • 我想嘗試擺脫或SQL2。這應該是可能的,當根條目具有它自己的ID作爲root_id

  • 假設你實際上需要的層次,我認爲是由分層查詢提供的,你可以預先計算表的層次到一列。然後,您可以刪除connect by子句,從而生成一個真正簡單的查詢。當然如果這樣做的話,很大程度上取決於你的應用程序的其他部分。

  • 你是否需要快速的所有行?或第一行?您可以嘗試提供相應的提示(http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm#4924)

+0

上只是一個拼寫錯誤我實際上想要獲得更好的性能。所以我想對此進行一些改進建議 –

0

基本上第一行正在尋找候選人在整個「森林」(即整個討論表,即300000行)中構建線程樹。當然,它試圖盡力而爲,但可能的解決方案的空間很大。

查詢2基本上說,「只得到我感興趣的樹的部分 - 你可以通過root ID識別,並從中構建整棵樹」。

看看數字o在兩個執行計劃中的f行,並查看自己在搜索空間的巨大差異。

如果您的搜索空間已經很小(例如,每次僅有4-5個元素的2次討論),第二個查詢的時間將由尋找小表中的少量行來支配......這個解釋了爲什麼第二個查詢可能對於幾乎爲空的表格「更糟糕」。

+0

謝謝,你有什麼想法來提高SQL的性能嗎? –

+0

取決於您是否可以重構當前表格,以及樹木的層數是否有上限。 Faroult(http://www.amazon.com/Art-SQL-Stephane-Faroult/dp/0596008945)專門研究了SQL中的樹結構,並提供了使用START WITH/CONNECT的替代方法。 –