2011-10-23 4 views
0

J'ai une table "discussion" dont la structure suit:Oracle problème de performances des requêtes

Nom de la table: discussion,

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 

Évidemment id a été défini comme PK, id_parent et ROOT_ID a été indexé.

ces lignes de table ont été construites comme une relation hiérarchique (sorte de parent-> enfant), ainsi que la colonne root_id est utilisée pour décrire ces lignes sont dans la même arborescence.

J'écrit deux SQLs pour obtenir l'arbre de fil:

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 

Après mon test, si les ensembles de données sont autour 4000, SQL 1 a fait un peu mieux que SQL2. Mais si la discussion de table a des données très volumineuses, SQL 2 a fait beaucoup mieux que SQL1. Lorsque la table contient 300 000 lignes, le plan de requête indique que le coût de SQL 1 est de 22126. Le coût de SQL 2 est de 6. SQL 1 est associé à un scan de table complet ou SQL 2 à un index de gamme.

Quelqu'un peut-il m'aider à expliquer pourquoi les deux SQL affichent un résultat différent avec un ensemble de données différent?

Plus important est que je veux vos suggestions de gars pour améliorer la performance ou une autre solution?

Voici le plan de requête pour SQL 1 lorsque nous avons 300 000 lignes.

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") 

Voici le plan de requête SQL pour lorsque nous avons 300 milliers de lignes.

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

désolé, il fonctionne avec la même table, Juste une erreur de sort sur sql –

Répondre

1

Vous voulez juste une explication de ce que vous voyez? Ou des suggestions pour améliorer cela?

En supposant que la première:

Avec SQL1 la base de données doit trouver l'élément racine, puis tous les enfants, les enfants de cela et ainsi de suite. Il doit toujours fonctionner avec la table complète car aucun filtre général n'est disponible. Il a traiter toute la table (ou l'index complet). Avec SQL2, la première chose que le système de base de données peut faire est de réduire le sous-ensemble de lignes sur lequel il travaille.

La différence est faible (ou même dans les directions opposées) pour les petites tables. Si la taille de la table est comprise entre un ou deux blocs, la base de données ne peut pas effectuer de filtrage utile. Il doit en tout cas tirer les blocs en mémoire. Encore plus s'il utilise l'accès à l'index. Mais avec une énorme table avec (juste pour composer des nombres) 100 blocs en réduisant ceux-ci à 5 soit en consultant 2 blocs d'index est d'abord un gain énorme.

Mise à jour: Quelques idées pour syntoniser ceci:

  • je vais essayer de se débarrasser du ou SQL2. Cela devrait être possible lorsqu'une entrée racine a son propre ID comme ID_racine

  • En supposant que vous ayez réellement besoin du niveau, que la requête hiérarchique me semble pouvoir fournir, vous pouvez précalculer le niveau dans une colonne de la table. Ensuite, vous pouvez supprimer la clause connect by, ce qui donne une véritable requête simple. Bien sûr, si cela fonctionne, cela dépend beaucoup du reste de votre application.

  • Avez-vous besoin de toutes les lignes rapidement? Ou les premiers rangs? Vous pouvez essayer de fournir l'indication appropriée (http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm#4924)

+0

Je veux réellement obtenir une meilleure performance un. Donc, je veux des suggestions pour améliorer ce –

0

Fondamentalement, la première ligne est à la recherche de candidats pour construire l'arbre de threads dans toute la "forêt" (c'est-à-dire toute la table de discussion, soit 300000 lignes.) Bien sûr, il essaie de faire de son mieux, mais l'espace des solutions possibles est grand. "N'obtient que les parties de l'arbre qui m'intéressent - que vous pouvez identifier grâce à l'identifiant de la racine, et en construire l'arbre entier"

Jetez un oeil au nombre de f rangées dans les deux plans d'exécution et de voir par vous-même la grande différence dans l'espace de recherche. Dans le cas où votre espace de recherche était déjà petit (disons, 2 discussions avec seulement 4-5 éléments dans chaque) le temps pour la deuxième requête serait dominé par la recherche d'un petit nombre de lignes dans une petite table ... ceci explique pourquoi la deuxième requête peut être "pire" pour une table presque vide.

+0

Merci, avez-vous des idées pour améliorer les performances de SQL? –

+0

Cela dépend si vous pouvez restructurer votre table actuelle, et s'il y a une limite supérieure au nombre de niveaux que vos arbres peuvent avoir. Faroult (http://www.amazon.com/Art-SQL-Stephane-Faroult/dp/0596008945) consacre un chapitre entier aux structures arborescentes en SQL, et il propose des alternatives à l'utilisation de START WITH/CONNECT. –

Questions connexes