sql >> Databáze >  >> RDS >> Oracle

Podivné změny rychlosti s dotazem SQL

Chcete-li lépe porozumět tomu, co se děje, zkuste toto:

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;

a poté:

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

Hádám, že na claim_key uvidíte řádek označující TABLE ACCESS FULL.

Pak zkuste:

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

a zkontrolujte, jaký index (pravděpodobně) používá. To by vám mělo poskytnout představu o tom, co databáze dělá, což vám pomůže zjistit proč dělá to.

Dobře, vzhledem k vašim plánům vysvětlení je to klasický příklad „indexy nejsou vždy dobré, skenování tabulek není vždy špatné“.

INDEX SKIP SCAN je místo, kde se databáze může pokusit použít index, i když není ani použit úvodní sloupec indexu. V zásadě, pokud váš index vypadal takto (příliš zjednodušeně):

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

a vaše podmínka byla WHERE col2 ='X' skenování přeskočení indexu říká, že prohlédněte každou kombinaci v COL1, kde col2 ='X'. Jakmile nalezne shodu (např. col1 =A, col2 =X), „přeskočí“ hodnoty v col1 dolů tam, kde se hodnota změní (col1 =B, poté col1 =C atd.) a hledá další shody.

Háček je v tom, že indexy (obecně!) fungují takto:1) najděte další rowid v indexu, kde byla hodnota nalezena, 2) přejděte na blok tabulky s tímto rowidem (TABLE ACCESS BY INDEX ROWID) 3) opakujte, dokud se již nebudou shodovat jsou nalezeny.

(V případě skenování přeskakováním by také vznikly náklady na zjištění, kde je další změna hodnoty u předních sloupců.)

To vše je dobré a dobré pro malý počet řádků, ale trpí zákonem klesajících výnosů; není to tak skvělé, když máte velký počet řádků. Je to proto, že musí číst blok indexu, pak blok tabulky, pak blok indexu, blok tabulky (i když byl blok tabulky dříve načten.)

Úplné skenování tabulky jen „probírá“ data částečně díky...multiblokovému čtení. Databáze dokáže přečíst mnoho bloků z disku při jediném čtení a nečte stejný blok více než jednou.

INDEX FAST FULL SCAN v podstatě zachází s I_CLAIM_KEY_002 jako s tabulkou. Na vše, co potřebujete v dotazu, může odpovědět samotný index; není vyžadován přístup k tabulce. (Předpokládám, že I_CLAIM_KEY_002 je definováno jako clnt_id, dte_of_srvce a buď clnt_id, nebo dte_of_srvce nemá hodnotu null. Protože ck.id by neměl být null atribut, počet na ck.id je stejný jako počet na ck.clnt_id.)

Takže pokud jde o váš počáteční dotaz, pokud nechcete změnit své indexy, zkuste toto:

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

což vynutí úplné prohledání tabulky na claim_key (ck) a můžete vidět podobný výkon jako ostatní dva. (Přesvědčte se, že se jedná o tento případ, nejprve před dotazem zadejte "explain plan set statement_id ='query_hint' for" a spusťte dotaz dbms_xplan, než jej spustíte.)

(Nyní se zeptáte „chci takové rady zadávat pořád“? Prosím ne. Toto je pouze pro test. Toto je jen pro kontrolu, zda je FTS lepší než INDEX SKIP SCAN . Pokud ano, musíte zjistit proč. :)

Každopádně...doufám, že to dávalo smysl..myslím smysl.



  1. Existují nějaké bezplatné nástroje pro generování skriptů 'INSERT INTO' v MS SQL Server?

  2. Jak správně volat funkce PostgreSQL (uložené procedury) v rámci Spring/Hibernate/JPA?

  3. Porovnání rovnosti/nerovnosti SQL s hodnotami s možnou hodnotou null

  4. Jak analyzovat vyhledávací řetězec uživatele pro dotaz Postgresql?