2011-10-23 7 views
0

나는 테이블 "토론"있는 구조를 따르고 있습니다오라클 쿼리 성능 문제

테이블 이름 :

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로 정의 하였다 토론, 색인하고있다.

이러한 테이블 행은 계층 적 관계 (parent-> child 정렬)로 작성되었으며 root_id 열은 동일한 트리에있는 행을 설명하는 데 사용됩니다.

나는 스레드 트리를 얻을 수있는 두 개의 SQL을 작성 :

SQL을 1

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

SQL 내 테스트 후

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

2

, 데이터 세트 주위에있는 경우 4000, SQL 1은 SQL2보다 조금 나아졌습니다. 그러나 테이블 토론의 데이터가 매우 큰 경우 SQL 2는 SQL1보다 훨씬 뛰어납니다.

테이블에 300,000 개의 행이있는 경우 쿼리 계획에 따르면 SQL 1의 비용은 22126이고 SQL 2의 비용은 6입니다. SQL 1은 전체 테이블 스캔 또는 SQL 2 범위 인덱스 스캔을 수행합니다.

두 명의 SQL이 다른 데이터 세트로 다른 결과를 표시하는 이유는 누구든지 설명 할 수 있습니까?

더 중요한 것은 귀하의 제안에 따라 성능 또는 다른 솔루션을 개선하고 싶습니다.

다음은 30030 개의 행이있을 때 SQL 1에 대한 쿼리 계획입니다. 우리는 300 개 수천 행이있을 때

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이에 대한 쿼리 계획이다.

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를 사용하면 데이터베이스 시스템에서 수행 할 수있는 첫 번째 작업은 작업중인 행의 하위 집합을 줄이는 것입니다.

작은 테이블의 차이는 작습니다 (또는 반대 방향 임). 전체 테이블이 하나 또는 두 개의 블록에 들어 맞는 경우 데이터베이스에서 수행 할 수있는 유용한 필터링이 많지 않습니다. 어쨌든 블록을 메모리로 가져와야합니다. 인덱스 액세스를 사용하는 경우 더 많은 기능을 제공합니다. 그러나 (단지 숫자를 만드는) 커다란 테이블을 가지고 100 블록을 줄이면이 ​​인덱스 블록을 2 번 컨설팅하는 것이 가장 큰 이득이됩니다.

업데이트 : 조정이에 대한 몇 가지 아이디어 :

  • 나는 또는 SQL2에서 제거하려고 할 것입니다. 루트 엔트리가 root_id로 자신의 ID를 가지고있을 때 가능해야합니다.

  • 실제로 계층 적 쿼리에서 제공한다고 생각되는 수준이 필요하다고 가정하면 레벨을 테이블 열로 미리 계산할 수 있습니다. 그런 다음 connect by 절을 삭제하여 실제 간단한 쿼리를 만들 수 있습니다. 물론이 방법이 효과가 있다면 나머지 응용 프로그램에 많이 의존해야합니다.

  • 모든 행을 빠르게해야합니까? 또는 첫 번째 행? 당신은 적절한 힌트 (http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm#4924)

+0

나는 실제로 더 나은 성능을 원한다. 그래서 나는 이것을 개선하기위한 몇 가지 제안을 원합니다. –

0

는 기본적으로 첫 번째 행을 찾고 제공 시도 할 수 있습니다 전체 "포레스트"(즉, 전체 토론 테이블, 즉 300,000 개의 행)에서 스레드 트리를 구성하는 후보자들. 물론 최선을 다하려고 노력하지만 가능한 솔루션의 공간은 넓습니다.

쿼리 2는 기본적으로 말합니다 , "관심있는 나무의 부분 만 가져 오십시오. 루트 ID 덕택으로 신원을 확인할 수 있고 그 나무 전체를 만들 수 있습니다."

숫자를 살펴보십시오. f 개의 행을 두 개의 실행 계획에 넣고 검색 공간에서 큰 차이가 있음을 직접 확인하십시오.

검색 공간이 이미 작은 경우 (두 개의 토론이 각각 4-5 개의 요소로 이루어진 2 개의 토론) 두 번째 쿼리의 시간은 작은 테이블에서 적은 수의 행을 찾는 것으로 결정됩니다. 두 번째 쿼리가 거의 빈 테이블에 대해 "악화"될 수있는 이유를 설명합니다.

+0

고맙습니다. SQL의 성능을 향상시키기위한 아이디어가 있습니까? –

+0

현재 테이블을 재구성 할 수 있는지, 트리에 가질 수있는 레벨 수의 상한선이 있는지에 따라 다릅니다. Faroult (http://www.amazon.com/Art-SQL-Stephane-Faroult/dp/0596008945)는 SQL의 트리 구조 전체를 다루고 START WITH/CONNECT 사용에 대한 대안을 제시합니다. –