Pergunta

Na Consulta 1 uma varredura completa da tabela está sendo executada mesmo que o ID é uma coluna indexada. Consulta 2 obtém o mesmo resultado, mas muito mais rápido. Se Consulta 1 é executado retornar uma coluna indexada, em seguida, ele retorna rapidamente, mas se colunas não-indexados são devolvidos ou toda a linha é, então, a consulta demora mais tempo.

Na Consulta 3 corre rápido, mas o 'código' coluna é um VARCHAR2 (10) em vez de um número (12) e está indexada da mesma forma que 'id'.

Por que a Consulta 1 não pegar que ele deve usar o índice? Existe algo que deve ser alterada para permitir colunas de números indexados para executar mais rápido?

[Consulta 1]

select a1.*
from people a1
where a1.id like '119%' 
and rownum < 5

Explicar Plano
Select ALL_ROWS
Custo: 67 Bytes: 2.592 Cardinality: 4
2 COUNT STOPKEY
1 QUADRO DE ACESSO completa Tabela pessoas
Custo: 67 Bytes: 3.240 cardinalidade: 5

[Consulta 2]

select a1.*
from people a1, people a2
where a1.id = a2.id
and a2.id like '119%' 
and rownum < 5

Explicar Plano
Select ALL_ROWS
Custo: 11 Bytes: 2.620 Cardinality: 4
5 COUNT STOPKEY
4 QUADRO DE ACESSO POR ROWID INDEX Mesa Pessoas
Custo: 3 Bytes: 648 Cardinality: 1 | 3 Nested Loops
Custo: 11 Bytes: 2.620 Cardinality: 4
1 ÍNDICE jejum completo INDEX SCAN people_IDX3
Custo: 2 Bytes: 54.796 Cardinality: 7.828
2 ÍNDICE GAMA SCAN INDEX people_IDX3
Custo: 2 Cardinality: 1

[Consulta 3]

select a1.*
from people a1
where a1.code like '119%' 
and rownum < 5

Explicar Plano
Select ALL_ROWS
Custo: 6 Bytes: 1.296 Cardinality: 2
3 COUNT STOPKEY
2 tabela de acesso por índice ROWID Mesa Pessoas
Custo: 6 Bytes: 1.296 Cardinality: 2
1 INDEX RANGE SCAN INDEX people_IDX4
Custo: 3 Cardinality: 2

Foi útil?

Solução

COMO condição de correspondência de padrões espera ver os tipos de caracteres como tanto do lado esquerdo e do lado direito operandos. Quando se encontra um número, ele converte-lo implicitamente para Char. Sua Consulta 1 é basicamente silenciosamente reescrito para isso:

SELECT a1.*
  FROM people a1
 WHERE TO_CHAR(a1.id) LIKE '119%'
   AND ROWNUM < 5

Isso acontece no seu caso, e isso é ruim para 2 motivos:

  1. A conversão é executada para cada linha, que é lento;
  2. Por causa de uma função (embora implícito) num ONDE predicado, Oracle é incapaz de usar o índice em coluna A1.ID.

Para contornar o problema, você precisa fazer uma das seguintes opções:

  1. Criar um baseado em função do índice na coluna A1.ID:

    CREATE INDEX people_idx5 ON people (TO_CHAR(id));

  2. Se você precisa combinar registros em 3 primeiros caracteres de coluna ID, criar outra coluna do tipo NÚMERO contendo apenas esses 3 caracteres e usar uma planície = operador nele.

  3. Criar um ID_CHAR separado coluna do tipo VARCHAR2 e preenchê-lo com TO_CHAR(id). Indexá-lo e usar em vez de ID em sua condição WHERE.

    É claro que se você optar por criar uma coluna adicional com base na coluna de ID existente, você precisa manter os 2 synchronized.You pode fazer isso em batch como um único UPDATE, ou em um gatilho ON-UPDATE, ou adicionar essa coluna para as instruções INSERT e UPDATE apropriadas em seu código.

Outras dicas

COMO é uma função string, então um índice numérico não pode ser usado como facilmente. No índice numérico, você terá 119120130, .., 1191,1192,1193 ..., 11921,11922 ... etc. Isso é todas as linhas que começam com o '119' não será no mesmo lugar, assim todo o índice tem de ser lido (daí o jejum completo SCAN). Em um índice baseado em caracteres que eles estarão juntos (por exemplo, '119', '1191', '11911', '120', ...) para uma melhor gama SCAN pode ser usado.

Se você estava procurando valores id em um determinado intervalo (por exemplo 119000-119999), em seguida, especificar que, como o predicado (id entre 119000 e 119999).

Optimizer decidiu que é mais rápido para fazer uma varredura da tabela, provavelmente devido ao baixo número de registros reais.

Além disso, você deve saber que a correspondência não-exata é sempre muito pior do que exata. Se o seu, onde foi "a1.id = '123456'", seria provavelmente usar o índice. Mas, novamente, mesmo índice leva duas leituras (primeiro encontrar um registro no índice, em seguida, ler o bloco de tabela) e por muito pequenas mesas que poderia decidir por varredura da tabela.

Tente colocar um toque em uma das suas consultas para forçá-lo a usar o índice desejado e, em seguida, verificar o seu plano: pode ser que (devido à inclinação ou o que for) a optimzer não levar o índice em conta, mas decide contra a usá-lo por causa do custo percebido.

A palavra-chave LIKE diz SQL que você está fazendo uma correspondência de expressão regular. Você nunca deve usar expressões regulares em SQL ou em qualquer biblioteca de programação até ter verificado as funções de cadeia disponíveis para ver se a consulta pode ser expressa simplesmente com eles. Neste caso, você pode mudar isso para um é igual a condição comparando apenas o substring que consiste nos 3 primeiros caracteres do código. No Oracle, este seria parecido com:

SELECT *
FROM people
WHERE SUBSTR(code,1,3) = '119'
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top