Ho avuto la possibilità di giocare con questo, e i miei precedenti commenti su NOT IN sono una falsa pista in questo caso. La cosa fondamentale è la presenza di NULL, ovvero se le colonne indicizzate hanno vincoli NOT NULL applicati.
Ciò dipenderà dalla versione del database che stai utilizzando, perché l'ottimizzatore diventa più intelligente con ogni versione. Sto usando 11gR1 e l'ottimizzatore ha utilizzato l'indice in tutti i casi tranne uno:quando entrambe le colonne erano nulle e non includevo NOT IN
clausola:
SQL> desc big_table
Name Null? Type
----------------------------------- ------ -------------------
ID NUMBER
COL1 NUMBER
COL2 VARCHAR2(30 CHAR)
COL3 DATE
COL4 NUMBER
Senza la clausola 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>
Quando ho doppiato il NOT IN
nella clausola, l'ottimizzatore ha scelto di utilizzare l'indice. Strano.
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>
Tanto per ripetere, in tutti gli altri casi, fintanto che una delle colonne indicizzate è stata dichiarata non nulla, l'indice è stato utilizzato per soddisfare la query. Questo potrebbe non essere vero nelle versioni precedenti di Oracle, ma probabilmente indica la strada da seguire.