За да разберете по-добре какво се случва, опитайте това:
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'));
Предполагам, че ще видите ред, указващ ПЪЛЕН ДОСТЪП ДО ТАБЛИЦА на clam_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
и вашето условие беше WHERE col2 ='X' сканирането за прескачане на индекса казва, че прегледайте всяка комбинация в COL1 за това, където col2 ='X'. Той "прескача" стойностите в col1, след като намери съвпадение (напр. col1 =A, col2 =X) до мястото, където стойността се променя (col1 =B, след това col1 =C и т.н.) и търси още съвпадения.
Уловката е, че индексите (като цяло!) работят по следния начин:1) намерете следващия ред в индекса, където е намерена стойността2) отидете до блока на таблицата с този ред (ДОСТЪП ДО ТАБЛИЦА ПО ИНДЕКС ROWID)3) повторете, докато няма повече съвпадения са намерени.
(За сканирането с прескачане, това също ще доведе до разходите за намиране къде е следващата промяна на стойността за водещите колони.)
Всичко това е добре и добре за малък брой редове, но страда от закона за намаляващата възвръщаемост; не е толкова страхотно, когато имате голям брой редове. Това е така, защото трябва да прочете индексен блок, след това блок таблица, след това блок индекс, блок таблица (дори ако блокът таблица е бил прочетен преди това.)
Пълното сканиране на таблицата просто „обработва“ данните благодарение отчасти на... многоблокови четения. Базата данни може да чете много блокове от диска с едно четене и не чете един и същ блок повече от веднъж.
INDEX FAST FULL SCAN основно третира I_CLAIM_KEY_002 като таблица. Всичко, от което се нуждаете в заявката, може да бъде отговорено само от индекса; не се изисква ДОСТЪП ДО ТАБЛИЦА. (Предполагам, че I_CLAIM_KEY_002 е дефиниран като clnt_id, dte_of_srvce и нито clnt_id, нито dte_of_srvce не могат да бъдат нулеви. Тъй като 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
което ще принуди пълно сканиране на таблица на claim_key (ck) и можете да видите подобна производителност като другите две. (Проверете дали случаят е такъв, като първо префиксирате заявката с "explain plan set statement_id ='query_hint' for" и изпълните заявката dbms_xplan, преди да я изпълните.)
(Сега ще попитате „Искам ли да поставям такива съвети през цялото време“? Моля, недейте. Това е само за тест. Това е само за да проверите дали FTS е по-добър от ИНДЕКСНОТО СКАНИРАНЕ Ако е така, тогава трябва да разберете защо. :)
Както и да е... надявам се, че има смисъл... искам да кажа.