Оптимизация предложения IN - PullRequest
3 голосов
/ 26 июля 2011

Я использую Oracle 10g. Вот мой запрос

select * from Entries 
where RefKey in (select RefKey 
                 from Entries 
                 where KeyStat = 1) 
and RefKey = Key;

Здесь RefKey, Key и KeyStat все проиндексированы. Таблица разбита на другой столбец, который здесь не используется. В этом запросе я выбираю мастер-ключ (если RefKey = Key, а затем мастер) в настоящее время активен (KeyStat = 1). Вот план выполнения этого запроса с использованием SQLTools 1.21 RC3.

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name           | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                |     1 |   270 |   218K  (1)| 00:43:37 |       |       |
|   1 |  NESTED LOOPS SEMI                  |                |     1 |   270 |   218K  (1)| 00:43:37 |       |       |
|   2 |   PARTITION RANGE ALL               |                |     1 |   262 |   218K  (1)| 00:43:37 |     1 |    12 |
|*  3 |    TABLE ACCESS FULL                | ENTRIES        |     1 |   262 |   218K  (1)| 00:43:37 |     1 |    12 |
|*  4 |   TABLE ACCESS BY GLOBAL INDEX ROWID| ENTRIES        |    10M|    77M|     3   (0)| 00:00:01 | ROWID | ROWID |
|*  5 |    INDEX RANGE SCAN                 | IND_ENTR_REFKEY|     1 |       |     2   (0)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------------------------

Меня беспокоит ID = 3 "TABLE ACCESS FULL". Если все столбцы, используемые в этом запросе, проиндексированы, тогда почему oracle выполняет полное сканирование таблицы.

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


Чтобы объяснить, почему подзапрос необходим: я выбираю всю партию, имеющую хотя бы один активный ключ. Refkey не уникален; например:

Key=1, RefKey=1, Stat=1 
Key=2, RefKey=1, Stat=0
Key=3, RefKey=2, Stat=1

Ответы [ 3 ]

5 голосов
/ 26 июля 2011

"Меня беспокоит ID = 3" TABLE ACCESS FULL ". Если все столбцы используемые в этом запросе индексируются, то почему оракул делает полный Таблица сканирования. "

Оптимизатор игнорирует индекс KEYSTAT. Я предполагаю, что это потому, что KEYSTAT не очень избирателен (относительно немного разных значений) и / или потому что эти значения равномерно распределены по всему диапазону таблицы ENTRIES. Если запрос будет попадать почти в каждый блок таблицы, FULL TABLE SCAN - лучший путь.

Это предположение подтверждается увеличением скорости, которую вы получаете, фильтруя подзапрос.

Как и другие предлагали, рефакторинг вашего оператора для удаления подзапроса был бы лучшим способом повысить производительность.


"Были бы миллионы записей, имеющих KeyStat = 0, только несколько 1000 будет иметь 1, поэтому использование индекса будет полезным. "

Перекошенное распределение данных часто является источником проблем с производительностью. Видите ли, дело в том, что база данных не знает , что KEYSTAT = 1 значительно более избирателен, чем KEYSTAT = 0. Если мы не скажем это, именно поэтому вы можете подумать о создании гистограмм при сборе статистики по этому индексу. Узнайте больше .

Обратите внимание, что гистограммы могут вызывать проблемы, а также решать их, особенно с запросами, которые используют переменные связывания вместо литералов. Итак, сделайте тест в песочнице, прежде чем запускать их в производство.

4 голосов
/ 26 июля 2011

Может быть, я что-то упускаю, но разве это не должно давать тот же результат?

1 голос
/ 26 июля 2011

Можете ли вы сделать

EXPLAIN PLAN FOR select * from Entries 
where RefKey in (select RefKey 
                 from Entries 
                 where KeyStat = 1) 
and RefKey = Key;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Вы должны получить план объяснения с кучей дополнительной информации в конце.В частности, вы заинтересованы в этой операции 3. Она не только выполняет полное сканирование таблицы, но и дает только количество строк / кардинальность 1. Действительно, это означает, что она не думает, что что-то найдет (как никогдадает нулевое значение).

Вы можете сказать, что он не ожидает когда-либо найти строку, потому что хотя операция 4 говорит о 10 миллионах строк, она дает стоимость «3» и того «2».это индекс стоимости.Он не ожидает, что сканирование из '3' найдет что-либо, поэтому он никогда не ожидает вставки значения в сканирование индекса, поэтому он никогда не увидит 10M строк.

Так что я вижу две проблемы.Во-первых, он не использует индекс KeyStat.Во-вторых, он недооценивает количество строк, возвращаемых совпадением.первая может быть вызвана несоответствием типов данных.Возможно, KeyStat является символьным значением.Может быть, это не ведущий столбец в индексе.Может быть, индекс был отключен (во время задания ETL?).

Нечетная оценка также наводит на мысль.Если бы столбец был ведущим столбцом в индексе, я бы ожидал, что статистика сработает так, что max_val столбца равен 1. Если он думает, что max_val равен нулю, это объяснило бы: «Вы не найдетечто угодно ", но также и то, что у него нет индекса для быстрого поиска max_val.

...