Pour mieux comprendre ce qui se passe, essayez ceci :
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;
puis :
select *
from table(dbms_xplan.display(statement_id=>'query1'));
Je suppose que vous verrez une ligne indiquant TABLE ACCESS FULL sur claim_key.
Alors essayez :
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'));
et vérifiez pour voir quel index il utilise (vraisemblablement). Cela devrait vous donner une idée de ce que fait la base de données, ce qui vous aide à comprendre pourquoi ça le fait.
Ok, compte tenu de vos plans d'explication, c'est un exemple classique de "les index ne sont pas toujours bons, les analyses de tables ne sont pas toujours mauvaises".
L'INDEX SKIP SCAN est l'endroit où la base de données peut essayer d'utiliser un index même si la colonne principale de l'index n'est même pas utilisée. En gros, si votre index ressemblait à ceci (trop simplifié) :
COL1 COL2 ROWID
A X 1 <--
A Y 2
A Z 3
B X 4 <--
B Y 5
B Z 6
et votre condition était WHERE col2 ='X', l'index saute l'analyse dit de regarder à travers chaque combinaison dans COL1 pour où col2 ='X'. Il "ignore" les valeurs de col1 une fois qu'il a trouvé une correspondance (par exemple, col1 =A, col2 =X) jusqu'à l'endroit où la valeur change (col1 =B, puis col1 =C, etc.) et recherche d'autres correspondances.
Le hic, c'est que les index (généralement !) fonctionnent comme ceci :1) trouvez le prochain rowid dans l'index où la valeur a été trouvée2) allez au bloc de table avec ce rowid (TABLE ACCESS BY INDEX ROWID) 3) répétez jusqu'à ce qu'il n'y ait plus de correspondances sont trouvés.
(Pour le saut d'analyse, cela entraînerait également le coût de la recherche du prochain changement de valeur pour les colonnes principales.)
C'est bien beau pour un petit nombre de lignes, mais souffre de la loi des rendements décroissants; ce n'est pas si génial quand vous avez un grand nombre de lignes. C'est parce qu'il doit lire un bloc d'index, puis un bloc de table, puis un bloc d'index, un bloc de table (même si le bloc de table a déjà été lu.)
L'analyse complète de la table "parcourt" simplement les données grâce en partie aux lectures multiblocs. La base de données peut lire plusieurs blocs du disque en une seule lecture et ne lit pas le même bloc plus d'une fois.
L'INDEX FAST FULL SCAN traite essentiellement I_CLAIM_KEY_002 comme une table. L'index seul peut répondre à tout ce dont vous avez besoin dans la requête ; aucun ACCÈS À LA TABLE n'est requis. (Je suppose que I_CLAIM_KEY_002 est défini comme clnt_id, dte_of_srvce et que clnt_id ou dte_of_srvce n'est pas nullable. Étant donné que ck.id doit être un attribut non nul, un décompte sur ck.id est identique à un décompte sur ck.clnt_id.)
Donc, comme pour votre requête initiale, à moins que vous ne vouliez modifier vos index, essayez ceci :
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
qui forcera une analyse complète de la table sur claim_key (ck) et vous pourrez voir des performances similaires à celles des deux autres. (Vérifiez que c'est le cas en préfixant d'abord la requête avec "explain plan set statement_id ='query_hint' for" et en exécutant la requête dbms_xplan avant de l'exécuter.)
(Maintenant, vous allez demander "est-ce que je veux mettre des indices comme ça tout le temps"? S'il vous plaît ne le faites pas. C'est pour un test seulement. C'est juste pour vérifier si un FTS est meilleur que l'INDEX SKIP SCAN . Si c'est le cas, alors vous devez savoir pourquoi. :)
Quoi qu'il en soit... J'espère que cela a du sens... Je veux dire du sens.