2011-10-23 132 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的替代方法。 –