sql >> Databasteknik >  >> RDS >> Oracle

Konstiga hastighetsändringar med sql-fråga

För att bättre förstå vad som händer, prova detta:

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;

och sedan:

select *
from table(dbms_xplan.display(statement_id=>'query1'));

Jag antar att du kommer att se en rad som anger TABELLÅTKOMST FULLSTÄNDIG på claim_key.

Försök sedan:

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'));

och kontrollera för att se vilket index den (förmodligen) använder. Det borde ge dig en uppfattning om vad databasen gör, vilket hjälper dig att ta reda på varför det gör det.

Ok, med tanke på dina förklarande planer är det ett klassiskt exempel på "index är inte alltid bra, tabellsökningar är inte alltid dåliga".

INDEX SKIP SCAN är där databasen kan försöka använda ett index även om den inledande kolumnen i indexet inte ens används. I princip om ditt index såg ut så här (alltför förenklat):

COL1   COL2   ROWID
A      X      1        <--
A      Y      2
A      Z      3
B      X      4        <--
B      Y      5
B      Z      6 

och ditt tillstånd var WHERE col2 ='X' indexhoppningsskanningen säger titta igenom varje kombination i COL1 för där col2 ='X'. Den "hoppar över" värdena i col1 när den har hittat en matchning (t.ex. col1 =A, col2 =X) ner till där värdet ändras (col1 =B, sedan col1 =C, etc.) och letar efter fler matchningar.

Haken är att index (i allmänhet!) fungerar så här:1) hitta nästa rad i indexet där värdet hittades2) gå till tabellblocket med den raden (TABELLÅTKOMST GENOM INDEX ROWID)3) upprepa tills inga fler matchningar hittas.

(För hoppa över skanningen skulle det också medföra kostnaden för att ta reda på var nästa värdeförändring är för de inledande kolumnerna.)

Detta är väl och bra för ett litet antal rader, men lider av lagen om minskande avkastning; det är inte så bra när du har ett stort antal rader. Det beror på att den måste läsa ett indexblock, sedan ett tabellblock, sedan ett indexblock, ett tabellblock (även om tabellblocket lästes tidigare.)

Den fullständiga tabellskanningen "plöjer" bara igenom data delvis tack vare...multiblock-läsningar. Databasen kan läsa många block från disk i en enda läsning och läser inte samma block mer än en gång.

INDEX FAST FULL SCAN behandlar i princip I_CLAIM_KEY_002 som en tabell. Allt du behöver i frågan kan enbart besvaras av indexet; ingen BORDTILLGÅNG krävs. (Jag antar att I_CLAIM_KEY_002 är definierad som clnt_id, dte_of_srvce och antingen clnt_id eller dte_of_srvce är inte nullbar. Eftersom ck.id ska vara ett inte null-attribut, är en räkning på ck.id detsamma som en count på ck.clnt_id.)

Så när det gäller din första fråga, om du inte vill ändra dina index, prova detta:

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

vilket kommer att tvinga fram en fullständig tabellsökning på claim_key (ck) och du kan se liknande prestanda som de andra två. (Kontrollera att detta är fallet genom att först prefixet frågan med "explain plan set statement_id ='query_hint' for" och köra dbms_xplan-frågan innan du kör den.)

(Nu kommer du att fråga "vill jag lägga in sådana tips hela tiden"? Snälla gör det inte. Detta är endast för ett test. Detta är bara för att kontrollera om en FTS är bättre än INDEX SKIP SCAN Om det är det, måste du ta reda på varför. :)

Hur som helst...Jag hoppas att det blev snese..Jag menar vettigt.



  1. PHP Kontrollera efter NULL

  2. Skjut vissa poster till slutet av en körning av samma datum

  3. index på url eller hashing med tanke på RAM

  4. Bryter MySQL mot standarden genom att tillåta att välja kolumner som inte är en del av gruppen för klausul?