Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Mudanças de velocidade estranhas com consulta sql


Para entender melhor o que está acontecendo, tente isto:
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;

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

Eu estou supondo que você verá uma linha indicando TABLE ACCESS FULL em Claim_key.

Então tente:
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'));

e verifique qual índice ele (presumivelmente) está usando. Isso deve lhe dar uma ideia do que o banco de dados está fazendo, o que ajuda a descobrir por que está fazendo isso.

Ok, dado seus planos de explicação, é um exemplo clássico de "índices nem sempre são bons, varreduras de tabelas nem sempre são ruins".

O INDEX SKIP SCAN é onde o banco de dados pode tentar usar um índice mesmo que a coluna inicial do índice não seja usada. Basicamente, se o seu índice ficou assim (excessivamente simplificado):
COL1   COL2   ROWID
A      X      1        <--
A      Y      2
A      Z      3
B      X      4        <--
B      Y      5
B      Z      6 

e sua condição era WHERE col2 ='X', a varredura de salto de índice diz olhar através de cada combinação em COL1 para onde col2 ='X'. Ele "pula" os valores em col1 quando encontra uma correspondência (por exemplo, col1 =A, col2 =X) até onde o valor muda (col1 =B, então col1 =C, etc.) e procura mais correspondências.

O problema é que os índices (geralmente!) funcionam assim:1) encontre o próximo rowid no índice onde o valor foi encontrado2) vá para o bloco da tabela com esse rowid (TABLE ACCESS BY INDEX ROWID)3) repita até que não haja mais correspondências são encontrados.

(Para a varredura de salto, também incorreria no custo de descobrir onde a próxima alteração de valor é para as colunas iniciais.)

Isso é muito bom para um pequeno número de linhas, mas sofre com a lei dos retornos decrescentes; não é tão bom quando você tem um grande número de linhas. Isso porque ele tem que ler um bloco de índice, depois um bloco de tabela, depois um bloco de índice, um bloco de tabela (mesmo que o bloco de tabela tenha sido lido anteriormente).

A varredura completa da tabela apenas "arra" os dados graças em parte às leituras de vários blocos. O banco de dados pode ler muitos blocos do disco em uma única leitura e não lê o mesmo bloco mais de uma vez.

O INDEX FAST FULL SCAN trata basicamente o I_CLAIM_KEY_002 como uma tabela. Tudo o que você precisa na consulta pode ser respondido apenas pelo índice; não é necessário ACESSO À TABELA. (Acho que I_CLAIM_KEY_002 é definido como clnt_id, dte_of_srvce e clnt_id ou dte_of_srvce não é anulável. Como ck.id não deve ser um atributo nulo, uma contagem em ck.id é o mesmo que uma contagem em ck.clnt_id.)

Então, quanto à sua consulta inicial, a menos que você queira reorganizar seus índices, tente isto:
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

o que forçará uma verificação completa da tabela em Claim_key (ck) e você poderá ver um desempenho semelhante aos outros dois. (Verifique se este é o caso primeiro prefixando a consulta com "explain plan set statement_id ='query_hint' for" e executando a consulta dbms_xplan antes de executá-la.)

(Agora você vai perguntar "eu quero colocar dicas assim o tempo todo"? Por favor, não. Isso é apenas para um teste. Isso é apenas para verificar se um FTS é melhor que o INDEX SKIP SCAN . Se for, então você precisa descobrir o porquê. :)

De qualquer forma... espero que tenha feito snese... quero dizer, sentido.