Чтобы лучше понять, что происходит, попробуйте это:
explain plan set statement_id = 'query1' for
SELECT count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5
AND ck.prgrm_id = 1;
и затем:
select *
from table(dbms_xplan.display(statement_id=>'query1'));
Полагаю, вы увидите строку, указывающую, что TABLE ACCESS FULL заполнен на Claim_key.
Тогда попробуйте:
explain plan set statement_id = 'query2' for
SELECT count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5;
select *
from table(dbms_xplan.display(statement_id=>'query2'));
и проверьте, какой индекс он (предположительно) использует. Это должно дать вам представление о том, что делает база данных, что помогает выяснить, почему делает это.
Хорошо, учитывая ваши планы объяснения, это классический пример "индексы не всегда хороши, сканирование таблиц не всегда плохое".
В INDEX SKIP SCAN база данных может попытаться использовать индекс, даже если ведущий столбец индекса даже не используется. В основном, если ваш индекс выглядел так (слишком упрощенно):
COL1 COL2 ROWID
A X 1 <--
A Y 2
A Z 3
B X 4 <--
B Y 5
B Z 6
и ваше состояние было ГДЕ col2 = 'X', сканирование с пропуском индекса говорит, что просматривайте каждую комбинацию в COL1, где col2 = 'X'. Он «пропускает» значения в столбце col1, как только найдет совпадение (например, col1 = A, col2 = X), до тех пор, пока значение не меняется (col1 = B, затем col1 = C и т. Д.), И ищет дополнительные совпадения.
Загвоздка в том, что индексы (как правило!) Работают так:
1) найти следующий идентификатор строки в индексе, где было найдено значение
2) перейти к блоку таблицы с этим rowid (TABLE ACCESS BY INDEX ROWID)
3) повторять до тех пор, пока больше не будет найдено совпадений.
(Для сканирования с пропуском это также повлечет за собой затраты на выяснение, где находится следующее изменение значения для ведущих столбцов.)
Это все хорошо для небольшого числа рядов, но страдает от закона убывающей отдачи; это не так здорово, когда у вас есть большое количество строк. Это потому, что он должен прочитать блок индекса, затем блок таблицы, затем блок индекса, блок таблицы (даже если блок таблицы был прочитан ранее).
Полное сканирование таблицы просто «пропускает» данные, отчасти благодаря ... многоблочному считыванию. База данных может читать много блоков с диска за одно чтение и не читает один и тот же блок более одного раза.
INDEX FAST FULL SCAN в основном рассматривает I_CLAIM_KEY_002 как таблицу. На все то, что вам нужно в запросе, можно ответить только по индексу; нет доступа к таблице не требуется. (Я предполагаю, что I_CLAIM_KEY_002 определен как clnt_id, dte_of_srvce, и либо clnt_id, либо dte_of_srvce не могут иметь значение null. Так как ck.id должен быть ненулевым атрибутом, число в ck.id равно количеству в ck.clnt_id.)
Что касается исходного запроса, если вы не хотите перенастроить свои индексы, попробуйте следующее:
SELECT /*+ FULL(ck) */ count(ck.id)
FROM claim_key ck
WHERE (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
AND ck.clm_type = 5
AND ck.prgrm_id = 1
, что приведет к полному сканированию таблицы для request_key (ck), и вы увидите производительность, аналогичную двум другим. (Убедитесь, что это так, сначала добавьте в запрос префикс «объяснение плана набора Statement_id = 'query_hint' for» и запустите запрос dbms_xplan перед его выполнением.)
(Теперь вы спросите: «Хочу ли я постоянно добавлять подобные подсказки?», Пожалуйста, не делайте этого. Это только для теста. Это просто для проверки, лучше ли FTS, чем INDEX SKIP SCAN. Если это так, то вам нужно выяснить, почему.:)
В любом случае ... Я надеюсь, что это чуток ... Я имею в виду.