2009-09-09 7 views
2

Oracle va-t-il aplatir plusieurs clauses entre elles si elles ont des données qui se chevauchent? Dans mon application, les utilisateurs peuvent créer des termes de recherche dynamiques, il est donc possible qu'il y ait des chevauchements de données. Est-ce qu'Oracle optimisera le SQL pour moi ou dois-je le calculer avant de créer le SQL?Oracle se chevauchant plusieurs fois entre les instructions

-à-dire

Select de xxtable WHERE id (entre 10 et 20) ou (ENTRE 18 ET 30)

aura-t-il être exécuté "tel quel" ou converti en:

id Sélectionnez de xxtable OERE id (ENTRE 10 ET 30)

Merci pour votre temps.

Répondre

2

Cela dépend de la requête sur la façon dont l'optimiseur va le gérer. Vous pouvez le tester à l'aide SQLPlus autotrace et regardant les informations prédicats (ce qui se fait sur la version Oracle 10.2.0.3):

SQL>set autot traceonly 
SQL> 
    1 select l 
    2 from (SELECT l 
    3   FROM (SELECT LEVEL l 
    4     FROM dual CONNECT BY LEVEL < 20 
    5    ) 
    6  ) 
    7 where l between 5 and 10 
    8*  or l between 7 and 15; 

11 rows selected. 

Elapsed: 00:00:00.21 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2403765415 

-------------------------------------------------------------------------------------- 
| Id | Operation      | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |  |  1 | 13 |  2 (0)| 00:00:01 | 
|* 1 | VIEW       |  |  1 | 13 |  2 (0)| 00:00:01 | 
|* 2 | CONNECT BY WITHOUT FILTERING|  |  |  |   |   | 
| 3 | FAST DUAL     |  |  1 |  |  2 (0)| 00:00:01 | 
-------------------------------------------------------------------------------------- 

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

    1 - filter("L">=5 AND "L"<=10 OR "L">=7 AND "L"<=15) 
    2 - filter(LEVEL<20) 


Statistics 
---------------------------------------------------------- 
      1 recursive calls 
      0 db block gets 
      0 consistent gets 
      0 physical reads 
      0 redo size 
     494 bytes sent via SQL*Net to client 
     403 bytes received via SQL*Net from client 
      3 SQL*Net roundtrips to/from client 
      1 sorts (memory) 
      0 sorts (disk) 
     11 rows processed 

Pas ré-écriture fait par l'optimiseur dans ce cas sur les critères d'où, mais si nous modifiez-le légèrement:

SQL> 
    1 select l 
    2 from (SELECT l 
    3   FROM (SELECT LEVEL l 
    4     FROM dual CONNECT BY LEVEL < 20 
    5    ) 
    6  ) 
    7 where l between 5 and 10 
    8*  or l between 7 and 10; 

6 rows selected. 

Elapsed: 00:00:00.20 

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 2403765415 

-------------------------------------------------------------------------------------- 
| Id | Operation      | Name | Rows | Bytes | Cost (%CPU)| Time  | 
-------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT    |  |  1 | 13 |  2 (0)| 00:00:01 | 
|* 1 | VIEW       |  |  1 | 13 |  2 (0)| 00:00:01 | 
|* 2 | CONNECT BY WITHOUT FILTERING|  |  |  |   |   | 
| 3 | FAST DUAL     |  |  1 |  |  2 (0)| 00:00:01 | 
-------------------------------------------------------------------------------------- 

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

    1 - filter("L"<=10 AND ("L">=5 OR "L">=7)) 
    2 - filter(LEVEL<20) 


Statistics 
---------------------------------------------------------- 
      0 recursive calls 
      0 db block gets 
      0 consistent gets 
      0 physical reads 
      0 redo size 
     388 bytes sent via SQL*Net to client 
     392 bytes received via SQL*Net from client 
      2 SQL*Net roundtrips to/from client 
      1 sorts (memory) 
      0 sorts (disk) 
      6 rows processed 

Sur ce, nous voyons que l'optimiseur reconnaît que les deux où les critères ont la même limite supérieure. Cela dépend donc de la requête quant à la façon dont l'optimiseur va le réécrire.

+1

Quelle bonne réponse! Merci! Je suppose que la façon sûre de le faire est de s'assurer que tout se fasse de ma part. – davidemm

4

Il vaut la peine de regarder ce qui se passe lorsque nous exécutons un essai sur une table réelle avec un index. Cet exemple de table contient 69 241 lignes et un index non unique sur COL_3, avec des statistiques.

Cas 1: yer de base deux chevauchement entre clauses

SQL> set autotrace traceonly exp 
SQL> 
SQL> select * from big_table 
    2 where col_3 between 0.8 and 1 
    3 or col_3 between 0.9 and 1.1 
    4/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3993303771 

------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   | 14737 | 805K| 176 (1)| 00:00:03 | 
|* 1 | TABLE ACCESS FULL| BIG_TABLE | 14737 | 805K| 176 (1)| 00:00:03 | 
------------------------------------------------------------------------------- 

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

    1 - filter("COL_3"<=1.1 AND "COL_3">=0.9 OR "COL_3"<=1 AND 
       "COL_3">=0.8) 

SQL> 

Upshot: L'indice est ignoré et une analyse complète de la table s'ensuit

Cas n ° 2: les clauses entre la part d'un borne supérieure

SQL> select * from big_table 
    2 where col_3 between 0.8 and 1.1 
    3 or col_3 between 0.9 and 1.1 
    4/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 1461639892 

----------------------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |   | 7924 | 433K| 114 (0)| 00:00:02 | 
| 1 | TABLE ACCESS BY INDEX ROWID| BIG_TABLE | 7924 | 433K| 114 (0)| 00:00:02 | 
|* 2 | INDEX RANGE SCAN   | BIG3_IDX | 7924 |  | 17 (0)| 00:00:01 | 
----------------------------------------------------------------------------------------- 

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

    2 - access("COL_3"<=1.1) 
     filter("COL_3">=0.8 OR "COL_3">=0.9) 

SQL> 

Upshot: L'indice est utilisé pour l'analyse limite supérieure et une table complète est évité

Cas n ° 3: les clauses BETWEEN partagent une limite inférieure

SQL> select * from big_table 
    2 where col_3 between 0.8 and 1.1 
    3 or col_3 between 0.8 and 1.2 
    4/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 3993303771 

------------------------------------------------------------------------------- 
| Id | Operation   | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |   | 15146 | 828K| 176 (1)| 00:00:03 | 
|* 1 | TABLE ACCESS FULL| BIG_TABLE | 15146 | 828K| 176 (1)| 00:00:03 | 
------------------------------------------------------------------------------- 

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

    1 - filter(("COL_3"<=1.2 OR "COL_3"<=1.1) AND "COL_3">=0.8) 

SQL> 

Upshot: L'indice est ignoré et un balayage de table complet s'ensuit

Cas 4: les deux plages BETWEEN sont fusionnées en une seule clause

SQL> select * from big_table 
    2 where col_3 between 0.8 and 1.1 
    3/

Execution Plan 
---------------------------------------------------------- 
Plan hash value: 1461639892 

----------------------------------------------------------------------------------------- 
| Id | Operation     | Name  | Rows | Bytes | Cost (%CPU)| Time  | 
----------------------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT   |   | 7924 | 433K| 114 (0)| 00:00:02 | 
| 1 | TABLE ACCESS BY INDEX ROWID| BIG_TABLE | 7924 | 433K| 114 (0)| 00:00:02 | 
|* 2 | INDEX RANGE SCAN   | BIG3_IDX | 7924 |  | 17 (0)| 00:00:01 | 
----------------------------------------------------------------------------------------- 

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

    2 - access("COL_3">=0.8 AND "COL_3"<=1.1) 

SQL> 

Upshot: L'indice est utilisé aussi bien pour les limites supérieure et inférieure

Donc, en résumé, si les deux clauses BETWEEN se chevauchent et il y a un index sur la colonne alors il pourrait être utile de la effort de les fusionner.

+1

+1 pour mettre en évidence l'effet potentiel sur la performance –

+0

J'utilise un index, donc c'était bon à savoir. Merci! – davidemm

Questions connexes