Eu tenho uma tabela com 250K linhas no meu banco de dados de teste. (Existem algumas centenas de milhões em produção, podemos observar o mesmo problema.) A tabela possui um identificador de seqüência de caracteres nvarchar2 (50), não nulo, com um índice exclusivo (não é o PK).
Os identificadores são compostos de uma primeira parte que possui 8 valores diferentes no meu banco de dados de teste (e cerca de mil em produção), depois um sinal @ e, finalmente, um número com 1 a 6 dígitos. Por exemplo, pode haver 50 mil linhas que começam com 'ABCD_BGX1741F_2006_13_20110808.xml @' e é seguido por 50 mil números diferentes.
Quando eu procuro uma única linha com base em seu identificador, a cardinalidade é estimada em 1, o custo é muito baixo e funciona bem. Quando eu procuro por mais de uma linha com vários identificadores em uma expressão IN ou OR, as estimativas para o índice estão completamente erradas, portanto, uma varredura de tabela completa é usada. Se eu forçar o índice com uma dica, é muito rápido, a verificação completa da tabela é realmente executada uma ordem de magnitude mais lenta (e muito mais lenta na produção). Portanto, é um problema do otimizador.
Como teste, dupliquei a tabela (no mesmo esquema + espaço de tabela) com exatamente o mesmo DDL e exatamente o mesmo conteúdo. Recriei o índice exclusivo na primeira tabela para uma boa medida e criei exatamente o mesmo índice na tabela de clones. Eu fiz um DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);
. Você pode até ver que os nomes dos índices são consecutivos. Portanto, agora a única diferença entre as duas tabelas é que a primeira foi carregada em ordem aleatória por um longo período de tempo, com blocos espalhados no disco (em um espaço de tabela juntamente com várias outras grandes tabelas), e a segunda foi carregada como um lote INSERIR-SELECIONAR. Fora isso, não consigo imaginar nenhuma diferença. (A tabela original foi reduzida desde a última grande exclusão e não houve uma única exclusão depois disso.)
Aqui estão os planos de consulta para a tabela de doentes e clones (as strings sob o pincel preto são as mesmas em toda a imagem e também sob o pincel cinza.):
(Neste exemplo, existem 1867 linhas que começam com o identificador escovado em preto. Uma consulta de 2 linhas produz uma cardinalidade de 1867 * 2, enquanto uma consulta de 3 linhas produz uma cardinalidade de 1867 * 3, etc. por coincidência, a Oracle parece não se importar com o fim dos identificadores.)
O que poderia causar esse comportamento? Obviamente, seria muito caro recriar a tabela em produção.
USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpg Eu só mudou o nome do esquema e tabela. Você pode ver que os nomes da tabela e do índice são os mesmos da captura de tela do plano de consulta.