Oracle
 sql >> Database >  >> RDS >> Oracle

Come posso ottenere un COUNT(col) ... GROUP BY per utilizzare un indice?

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.