Как я могу получить COUNT (col) ... GROUP BY для использования индекса? - PullRequest
2 голосов
/ 29 апреля 2010

У меня есть таблица (col1, col2, ...) с индексом (col1, col2, ...). Таблица содержит миллионы строк, и я хочу выполнить запрос:

 SELECT col1, COUNT(col2) WHERE col1 NOT IN (<couple of exclusions>) GROUP BY col1

К сожалению, это приводит к полному сканированию таблицы, которое занимает более минуты. Есть ли способ заставить оракула использовать индекс по столбцам для гораздо более быстрого возврата результатов?

EDIT:

более конкретно, я выполняю следующий запрос:

SELECT owner, COUNT(object_name) FROM all_objects GROUP BY owner

и существует индекс SYS.OBJ$ (SYS.I_OBJ2), который индексирует столбцы owner# и name; Я считаю, что я должен иметь возможность использовать этот индекс в запросе, а не полное сканирование таблицы SYS.OBJ$

Ответы [ 4 ]

3 голосов
/ 29 апреля 2010

У меня была возможность поиграть с этим, и мои предыдущие комментарии относительно NOT IN в этом случае - красная сельдь. Ключевым моментом является наличие NULL, или, точнее, наличие в индексированных столбцах ограничений NOT NULL.

Это будет зависеть от версии базы данных, которую вы используете, потому что оптимизатор становится умнее с каждым выпуском. Я использую 11gR1, и оптимизатор использовал индекс во всех случаях, кроме одного: когда оба столбца были нулевыми, и я не включил предложение NOT IN:

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

Без предложения 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>

Когда я снова добавил предложение NOT IN, оптимизатор решил использовать индекс. Weird.

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>

Просто повторюсь, что во всех других случаях, пока один из проиндексированных столбцов был объявлен не nill, индекс использовался для удовлетворения запроса. Это может быть неверно в более ранних версиях Oracle, но, вероятно, указывает путь вперед.

0 голосов
/ 06 мая 2010

Вы запрашиваете фиксированные таблицы оракула, так как вы не указали, что это за db vesion, я полагаю, что недавно. Были ли проанализированы фиксированные таблицы и обновлена ​​ли статистика? Вы пробовали свой запрос с помощью оптимизатора базы правил, используя подсказку / * + rule * /. Часто я видел, что запросы к собственным фиксированным таблицам oracle работают лучше, когда используется оптимизатор базы правил.

0 голосов
/ 29 апреля 2010

(На всякий случай, вы уверены, что выполняется сканирование таблицы, а не сканирование индекса?)

Попробуйте использовать COUNT(*) вместо COUNT(col2) (конечно, если это подходит для вашей проблемы). Кроме того, возможно, попробуйте индекс только с col1.

0 голосов
/ 29 апреля 2010

вы можете использовать подсказку http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm, но помните, что использование индекса не всегда приводит к более быстрому выполнению.

...