Oracle SQL - выберите не использовать индекс, как ожидалось - PullRequest
0 голосов
/ 10 марта 2020

Так что я не использовал Oracle более 5 лет, и я не практикуюсь. Я все это время был на SQL сервере.

Я смотрю на некоторые из существующих запросов и пытаюсь их улучшить, но они реагируют очень странно. В соответствии с планом объяснения вместо того, чтобы идти быстрее, они вместо этого выполняют полное сканирование таблицы и не используют индексы.

В исходном запросе выполняется равенство между двумя таблицами, выполненными в операторе where. Мы назовем их таблицами A и B. Я использовал план объяснения, за которым следовала таблица SELECT * FROM (DBMS_XPLAN.DISPLAY (FORMAT => 'ALL + OUTLINE')); и он говорит мне, что таблица A запрашивается с помощью локального индекса.
ДОСТУП К ТАБЛИЦЕ ПО ЛОКАЛЬНОМУ ИНДЕКСУ ROWID

SELECT A.* 
FROM TableA  A, TableB B 
WHERE A.SecondaryID = B.ID;

Я попытался изменить запрос и присоединить TableA к новой таблице (Таблица C) , Таблица C является подмножеством таблицы B с 700 записями вместо 100K. Однако план объяснения говорит мне, что таблица A теперь запрашивается с полным поиском.

CREATE TableC 
AS<br>
SELECT * FROM TableB WHERE Active='Y';



SELECT A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

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

SELECT /*+ INDEX (A_NDX01) */ A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

Поэтому я попытался перейти от объединения к простому выбору таблицы A и использовать оператор IN для сравнения с таблицей C , Все еще полное сканирование таблицы.

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC);

Наконец, я взял предыдущий оператор и изменил подвыбор, чтобы получить первые 1000 записей, и он использовал индекс. Странно то, что в таблице всего 700 записей C.

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC WHERE rownum <1000

)

Мне было интересно, может ли кто-нибудь помочь мне выяснить, что происходит?
Мой лучший Предполагается, что поскольку Table C является новой таблицей, может быть, оптимизатор не знает, сколько в ней записей, и поэтому он будет использовать индекс только в том случае, если знает, что записей меньше 1000?
Я попытался запустить dbms_stats.gather_schema_stats в своей схеме, но это не помогло.
Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 10 марта 2020

Как правило, использование индекса не обязательно сделает ваш запрос go ВСЕГДА быстрее.

Подсказки - это директивы оптимизатору для использования пути, это означает, что оптимизатор выберет подчинение директиве подсказки. В этом случае оптимизатор посчитал бы, что поиск индекса в таблице A дороже в

SELECT A.* 
FROM TableA  A, TableB B 
WHERE A.SecondaryID = B.ID;

SELECT /*+ INDEX (A_NDX01) */ A.* 
FROM TableA  A, TableC C 
WHERE A.SecondaryID = C.ID;

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC);

Внутренне он мог бы преобразовать все эти операторы (IN) в объединение, которое при рассмотрении данных в таблица A и таблица C решили использовать полное сканирование таблицы.

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

Я полагаю, что это происходит, когда вы сделали

SELECT A.* 
FROM TableA  A 
WHERE A.SecondaryID in (SELECT ID FROM TableC WHERE rownum <1000)

Посмотрите на следующее ссылка

Oracle. Предотвращение подзапроса слияния и основных условий запроса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...