Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Wie kann ich ein COUNT(col) ... GROUP BY erhalten, um einen Index zu verwenden?

Ich hatte die Gelegenheit, damit herumzuspielen, und meine vorherigen Kommentare bezüglich NOT IN sind in diesem Fall ein Ablenkungsmanöver. Das Wichtigste ist das Vorhandensein von NULL-Werten, oder besser gesagt, ob für die indizierten Spalten NOT-NULL-Einschränkungen erzwungen werden.

Dies hängt von der Version der Datenbank ab, die Sie verwenden, da der Optimierer mit jeder Version intelligenter wird. Ich verwende 11gR1 und der Optimierer hat den Index in allen Fällen verwendet, außer in einem:als beide Spalten null waren und ich NOT IN nicht eingeschlossen habe Klausel:

SQL> desc big_table
 Name                                  Null?    Type
 -----------------------------------  ------    -------------------
 ID                                             NUMBER
 COL1                                           NUMBER
 COL2                                           VARCHAR2(30 CHAR)
 COL3                                           DATE
 COL4                                           NUMBER

Ohne die NOT IN-Klausel...

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>

Als ich den NOT IN getippt habe -Klausel wieder eingefügt, hat sich der Optimierer für die Verwendung des Index entschieden. Seltsam.

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>

Um es noch einmal zu wiederholen:In allen anderen Fällen wurde der Index verwendet, um die Abfrage zu erfüllen, solange eine der indizierten Spalten als nicht null deklariert wurde. Dies trifft möglicherweise nicht auf frühere Versionen von Oracle zu, weist aber wahrscheinlich den Weg nach vorn.