Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Como posso obter um COUNT(col) ... GROUP BY para usar um índice?


Eu tive a chance de brincar com isso, e meus comentários anteriores sobre o NOT IN são um arenque vermelho neste caso. O principal é a presença de NULLs, ou melhor, se as colunas indexadas têm restrições NOT NULL aplicadas.

Isso vai depender da versão do banco de dados que você está usando, porque o otimizador fica mais inteligente a cada lançamento. Estou usando 11gR1 e o otimizador usou o índice em todos os casos, exceto um:quando ambas as colunas eram nulas e não incluí o NOT IN cláusula:
SQL> desc big_table
 Name                                  Null?    Type
 -----------------------------------  ------    -------------------
 ID                                             NUMBER
 COL1                                           NUMBER
 COL2                                           VARCHAR2(30 CHAR)
 COL3                                           DATE
 COL4                                           NUMBER

Sem a cláusula 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 eu dobrei o NOT IN cláusula de volta, o otimizador optou por usar o índice. Esquisito.
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>

Apenas para repetir, em todos os outros casos, desde que uma das colunas indexadas fosse declarada não nula, o índice era usado para satisfazer a consulta. Isso pode não ser verdade em versões anteriores do Oracle, mas provavelmente aponta o caminho a seguir.