Pergunta

Eu tenho esta tabela:

create table demo (
    key number(10) not null,
    type varchar2(3) not null,
    state varchar2(16) not null,
    ... lots more columns ...
)

e este índice:

create index demo_x04 on demo(key, type, state);

Quando eu executar esta consulta

select * from demo where key = 1 and type = '003' and state = 'NEW'

EXPLAIN PLAN mostra que ele faz uma varredura completa na tabela.Então, eu deixei cair o índice e criado novamente. EXPLAIN PLAN ainda diz digitalização completa da tabela.Como pode ser isso?

Alguns antecedentes:Este é o histórico de dados, então o que acontece é que eu olhar para cima uma linha com o estado CLEARED e inserir uma nova linha com o estado NEW (além disso, eu copiar alguns valores da antiga linha).A linha antiga, em seguida, atualizado para USED.Assim, a tabela sempre cresce.O que notei é que a cardinalidade do índice é de 0 (apesar do fato de que eu tenho milhares de valores diferentes).Depois de recriar, a cardinalidade cresceu, mas o CBO não como o índice melhor.

Na manhã seguinte, Oracle, de repente, gostei do índice (provavelmente dormia sobre ele) e comecei a usá-lo, mas não por muito tempo.Depois de um tempo, o processamento caiu de 50 linhas/s para 3 linhas/s e vi novamente "FULL TABLE SCAN".O que está acontecendo?

No meu caso, eu preciso de processar cerca de um milhão de linhas.Eu confirmar as alterações em lotes de ca.50.Existe algum comando que eu deveria executar após uma confirmação para a actualização/reorganização do índice, ou algo assim?

Eu estou no Oracle 10g.

[EDITAR] eu tenho 969'491 chaves diferentes na tabela, 3 tipos e 3 estados.

Foi útil?

Solução

O que acontece se você especificar uma dica de índice? Experimente isso:

SELECT /*+ INDEX (demo demo_x04) */ * 
  FROM demo 
 WHERE key = 1 
   AND type = '003' 
   AND state = 'NEW';

Parece que o que aconteceu da noite para o dia foi que a mesa foi analisada. Então, ao executar seu processamento contra a tabela, o índice suficiente foi atualizado para fazer com que as estatísticas da tabela da Oracle fiquem obsoletas novamente e o otimizador parou de usar o índice.

Adicione a dica e veja se o Plano de Explicação fornece um plano diferente e a consulta tem um desempenho melhor.

Ah, e a resposta de Tony sobre a análise da tabela é uma boa prática geral, embora com 10g o banco de dados seja muito bom em fazer auto-manutenção nesse sentido. Se o seu processo estiver fazendo muitas atualizações, o índice pode ficar obsoleto rapidamente. Se a execução da análise quando seu processo começar a entrar na vala, melhora a situação por um tempo, você saberá que esse é o problema.

Para atualizar as estatísticas para a tabela, use o DMBS_STATS.GATHER_TABLE_STATS pacote.

Por exemplo:

EXEC DBMS_STATS.GATHER_TABLE_STATS ('O PROPRIETÁRIO', 'Demo');

Outras dicas

A tabela foi analisada recentemente? Se o Oracle acha que é muito pequeno, pode nem considerar o uso do índice.

Experimente isso:

select last_analyzed, num_rows 
from user_tables
where table_name = 'DEMO';

Num_Rows informa quantas linhas o Oracle pensa que a tabela contém.

"Na manhã seguinte, Oracle, de repente, gostei do índice (provavelmente dormia sobre ele)" Provavelmente um DBMS_STATS está em execução durante a noite.

Geralmente eu gostaria de ver um dos três motivos para uma VARREDURA COMPLETA na TABELA através de um índice.A primeira é que o otimizador considera que a tabela está vazia, ou pelo menos muito pequeno.Eu suspeito que esse foi o problema inicial.Nesse caso, seria mais rápida, verificação completa uma tabela consiste de apenas um punhado de blocos ao invés de utilizar um índice.

A segunda é quando a consulta é tal que um índice não pode ser praticamente utilizado.

"select * from demo where key = 1 and type = '003' and state = 'NEW'"

Você está realmente usando literais embutida na consulta.Se não, a variável tipos de dados podem estar incorretos (por exemplo, chave de caracteres).O que exigem que a tecla numérica ser convertidos em caracteres, para fins de comparação, o que tornaria o índice quase inútil.

A terceira razão é onde ele considera que a consulta irá processar uma grande proporção de linhas na tabela.Tipo e Estado parecem muito baixa cardinalidade.Você talvez tenha um grande número de um determinado "chave" valor ?

Um comentário sobre o processamento que você descreve: parece que você está fazendo processamento de linha a fila com compromissos intermitentes, e recomendo que você repense isso, se puder. O mecanismo de atualização/inserção pode muito bem ser convertido em uma instrução Merge e todo o conjunto de dados pode ser processado em uma única instrução com uma confirmação no final. Isso quase certamente seria mais rápido e usaria menos recursos do que o seu método atual.

O valor da chave da coluna é sempre 1? Nesse caso, não tenho certeza de que consultar o índice otimizaria a consulta, pois cada linha teria que ser examinada de qualquer maneira. Nesse caso, declare o índice sem a coluna da chave. Você também pode tentar:

select key, type, state from demo where key = 1 and type = '003' and state = 'NEW'

Qual (se meu palpite estiver certo) ainda precisaria olhar para cada linha, mas que pode ir para o índice, pois todas as colunas no conjunto de resultados agora estão cobertas.

Estou apenas supondo com base na sua declaração que o índice mostra a cardinalidade 0.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top