Oracle
 sql >> Base de données >  >> RDS >> Oracle

Comment puis-je obtenir un COUNT(col) ... GROUP BY pour utiliser un index ?

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.