Oracle
 sql >> база данни >  >> RDS >> Oracle

Странни промени в скоростта с sql заявка

За да разберете по-добре какво се случва, опитайте това:

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 е по-добър от ИНДЕКСНОТО СКАНИРАНЕ Ако е така, тогава трябва да разберете защо. :)

Както и да е... надявам се, че има смисъл... искам да кажа.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle APEX - справочна таблица с няколко връзки

  2. ORA-24408:не можа да генерира уникално име на група сървъри

  3. LINQPad и Oracle

  4. Защо не можете да използвате OR или IN с операция OUTER JOIN?

  5. Разбивате голям брой редове на по-малки заявки? Паралелизъм