J'ai eu la chance de jouer avec cela, et mes commentaires précédents concernant le NOT IN sont un faux-fuyant dans ce cas. L'élément clé est la présence de valeurs NULL, ou plutôt si les colonnes indexées ont des contraintes NOT NULL appliquées.
Cela dépendra de la version de la base de données que vous utilisez, car l'optimiseur devient plus intelligent à chaque version. J'utilise 11gR1 et l'optimiseur a utilisé l'index dans tous les cas sauf un :lorsque les deux colonnes étaient nulles et que je n'ai pas inclus le NOT IN
clause :
SQL> desc big_table
Name Null? Type
----------------------------------- ------ -------------------
ID NUMBER
COL1 NUMBER
COL2 VARCHAR2(30 CHAR)
COL3 DATE
COL4 NUMBER
Sans la clause NOT IN...
SQL> explain plan for
2 select col4, count(col1) from big_table
3 group by col4
4 /
Explained.
SQL> select * from table(dbms_xplan.display)
2 /
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
Plan hash value: 1753714399
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 31964 | 280K| | 7574 (2)| 00:01:31 |
| 1 | HASH GROUP BY | | 31964 | 280K| 45M| 7574 (2)| 00:01:31 |
| 2 | TABLE ACCESS FULL| BIG_TABLE | 2340K| 20M| | 4284 (1)| 00:00:52 |
----------------------------------------------------------------------------------------
9 rows selected.
SQL>
Quand j'ai doublé le NOT IN
clause de retour, l'optimiseur a choisi d'utiliser l'index. Bizarre.
SQL> explain plan for
2 select col4, count(col1) from big_table
3 where col1 not in (12, 19)
4 group by col4
5 /
Explained.
SQL> select * from table(dbms_xplan.display)
2 /
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
Plan hash value: 343952376
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 31964 | 280K| | 5057 (3)| 00:01:01 |
| 1 | HASH GROUP BY | | 31964 | 280K| 45M| 5057 (3)| 00:01:01 |
|* 2 | INDEX FAST FULL SCAN| BIG_I2 | 2340K| 20M| | 1767 (2)| 00:00:22 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
2 - filter("COL1"<>12 AND "COL1"<>19)
14 rows selected.
SQL>
Juste pour répéter, dans tous les autres cas, tant qu'une des colonnes indexées était déclarée non nulle, l'index était utilisé pour satisfaire la requête. Ce n'est peut-être pas vrai sur les versions antérieures d'Oracle, mais cela indique probablement la voie à suivre.