For bedre at forstå, hvad der foregår, prøv dette:
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;
og derefter:
select *
from table(dbms_xplan.display(statement_id=>'query1'));
Jeg gætter på, at du vil se en linje, der angiver TABELADGANG FULD på claim_key.
Prøv derefter:
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'));
og tjek for at se, hvilket indeks den (formodentlig) bruger. Det burde give dig en idé om, hvad databasen gør, hvilket hjælper med at finde ud af hvorfor det gør det.
Ok, givet dine forklarende planer, er det et klassisk eksempel på "indekser er ikke altid gode, tabelscanninger er ikke altid dårlige".
INDEX SKIP SCAN er der, hvor databasen kan forsøge at bruge et indeks, selvom den forreste kolonne i indekset ikke engang bruges. Grundlæggende hvis dit indeks så sådan ud (alt for forenklet):
COL1 COL2 ROWID
A X 1 <--
A Y 2
A Z 3
B X 4 <--
B Y 5
B Z 6
og din tilstand var WHERE col2 ='X', indeksspringsscanningen siger, se gennem hver kombination i COL1 for hvor col2 ='X'. Den "springer" værdierne i col1 over, når den har fundet et match (f.eks. col1 =A, col2 =X) ned til, hvor værdien ændres (col1 =B, derefter col1 =C osv.) og leder efter flere matches.
Fangsten er, at indekser (generelt!) fungerer sådan:1) find den næste række i indekset, hvor værdien blev fundet2) gå til tabelblokken med den række (TABELADGANG VED INDEX ROWID)3) gentag indtil der ikke er flere matches findes.
(For overspringsscanningen vil det også medføre omkostningerne ved at finde ud af, hvor den næste værdiændring er for de førende kolonner.)
Dette er alt sammen godt og vel for et lille antal rækker, men lider under loven om aftagende afkast; det er ikke så godt, når du har et stort antal rækker. Det er fordi den skal læse en indeksblok, derefter en tabelblok, så en indeksblok, en tabelblok (selvom tabelblokken tidligere blev læst.)
Den fulde tabelscanning "pløjer" bare gennem dataene, delvist takket være...multiblok-læsninger. Databasen kan læse mange blokke fra disk i en enkelt læsning og læser ikke den samme blok mere end én gang.
INDEX FAST FULL SCAN behandler grundlæggende I_CLAIM_KEY_002 som en tabel. Alt hvad du har brug for i forespørgslen kan besvares af indekset alene; der kræves ingen BORDADGANG. (Jeg gætter på, at I_CLAIM_KEY_002 er defineret som clnt_id, dte_of_srvce og enten clnt_id eller dte_of_srvce er ikke nullbar. Da ck.id skal være en ikke null-attribut, er en count on ck.id det samme som en count on ck.clnt_id.)
Så med hensyn til din indledende forespørgsel, medmindre du vil ændre dine indekser, så prøv dette:
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
hvilket vil fremtvinge en fuld tabelscanning på claim_key (ck), og du kan se lignende ydeevne som de to andre. (Kontroller, at dette er tilfældet, før forespørgslen præfikser med "explain plan set statement_id ='query_hint' for" og kør dbms_xplan-forespørgslen, før du kører den.)
(Nu vil du spørge "vil jeg indsætte den slags hints hele tiden"? Lad være med det. Dette er kun til en test. Dette er bare for at kontrollere, om en FTS er bedre end INDEX SKIP SCAN. Hvis det er det, så skal du finde ud af hvorfor. :)
Anyways...Jeg håber, det gav snese..Jeg mener mening.