Pergunta

Quais são algumas coisas que eu posso fazer para melhorar a consulta de desempenho de uma consulta oracle sem criar índices?

Aqui está a consulta que estou tentando correr mais rápido:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

Nenhuma destas colunas são indexados e cada uma das tabelas contém milhões de registros. Escusado será dizer, que leva mais de 3 minutos e meio para a consulta para executar. Esta é uma terceira base de dados festa em um ambiente de produção e eu não estou autorizado a criar os índices de modo que qualquer melhoria de desempenho teria que ser feito para a própria consulta.

Obrigado!

Foi útil?

Solução

Primeiro eu reescrever a consulta para ser padrão ANSI:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC

Isto torna mais fácil de ler e entender o que está acontecendo. Ele também ajuda a não cometer erros (ou seja Cruz Unir) que podem causar reais grandes problemas. Então eu ia ficar o plano para ver o que o DBMS está fazendo com essa consulta Explique. Ele está tentando usar alguns índices? Trata-se de juntar as tabelas corretamente?

Então eu rever as tabelas que eu estou trabalhando com para ver se existem índices que já existem que eu poderia estar usando para fazer a minha consulta mais rápida. Finalmente, como todos os outros tem sugerido que eu remover a cláusula ORDER BY e apenas fazer isso no código.

Outras dicas

Peça ao terceiro para indexar a sua juntar-se colunas, como deveriam ter feito em primeiro lugar! Sem índices, a Oracle não tem nada a ir para além da força bruta.

Você pode querer tentar criar uma visão materializada em qualquer uma dessas tabelas. Você pode criar um índice na visão materializada que irá acelerar a consulta (que seria, então, consultando a visão em vez da tabela raw materializado) de ajuda.

É claro que, se a tabela subjacente é atualizado seu ponto de vista e os índices precisam ser atualizados.

Em primeiro lugar, olhar para o plano de execução. Ela reflete com precisão o número de linhas a ser recuperado em cada fase da execução da consulta? Como seletiva é o predicado "a.ItemType IN (112115189241)"? Será que o plano de execução mostra qualquer uso de espaço em disco temporário para junta ou tipos?

Na verdade, talvez você pode modificar a pergunta para incluir o plano de execução.

Também certifique-se que você não tem hash com deficiência, que às vezes é o caso em sistemas OLTP-sintonizados, pois eles são a forma mais eficiente de equijoining dados em massa em Oracle. Eles deveriam mostrar-se no plano de execução.

Você pode tentar a filtragem de tipo de item antes de se juntar suas tabelas, como mostrado aqui.

Se você estiver executando o Oracle 9i antes, isso às vezes dão benefícios surpreendentes.

select 
  c.claimnumber,
  a.itemdate, 
  c.dtn,
  b.filepath
from 
  (
  select itemdate
  from items it
  where it.itemtype in(112,115,189,241)
  ) a
  itempages b,
  keygroupdata c
where a.itemnum = b.itemnum
  and b.itemnum = c.itemnum

Você também pode tentar adicionar as dicas / + REGRA / ou / + ORDERED / para ver o que acontece ... novamente, particularmente com versões mais antigas, estes, às vezes, dar resultados surpreendentes.

SELECT /*+RULE*/
  c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
  items a,
  itempages b,
  keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
  AND a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

Se as entradas de consulta são constante ou previsível (o itemType IN (...)), em seguida, uma alternativa seria a de executar a consulta uma vez ou duas vezes por dia e armazenar os resultados em uma tabela local, com índices sempre que necessário.

Você pode então fazer a consulta caro 'offline' e têm mais rápido / melhores resultados para uma consulta interativa.

Esta é uma consulta que você executa com frequência? Parece que seria do interesse do proprietário do banco de dados para criar os índices que você precisa para acelerar esta consulta para cima. Os 3,5 minutos você está gastando executar a consulta deve ter algum impacto no seu ambiente de produção!

Além disso, eles têm funcionado atualizar estatísticas sobre as mesas? Isso pode melhorar o desempenho, como a ordem de junção é calculado com base nas estatísticas das tabelas.

BTW, o que você está autorizado a fazer? Apenas leia? Se você pode criar tabelas temporárias e colocar índices sobre aqueles, eu poderia considerar fazer cópias temporárias de mesa, indexando os e, em seguida, fazer a junção com os temporários cópias. Assistida-index

Eu sei que esta discussão é muito antiga, mas para os motores de busca que eu ainda queria oferecer uma solução alternativa que irá funcionar em Oracle e dependendo dos dados pode ser muito mais rápido.

with a as (
  select 
    * 
  from 
    items 
  where 
    ItemType IN (112,115,189,241)
)
SELECT 
  c.ClaimNumber
  , a.ItemDate
  , c.DTN, b.FilePath
FROM 
  a,
  itempages b,
  keygroupdata c
WHERE 
  a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY 
  a.DateStored DESC

Você também pode tentar a dica /*+ MATERIALIZE */ na cláusula WITH.

Na verdade eu acho sintaxe antiga juntar-se da Oracle muito mais fácil de ler do que ansi sql ^^

Sem indexação, essa consulta só vai piorar à medida que aumenta o tamanho da tabela. Com isso dito, tente remover o fim da cláusula e fazer esse tipo no lado do cliente.

Às vezes você pode ver um benefício, acrescentando caminhos extras para o otimizador para escolher, adicionando o que parece ser elementos redundantes à cláusula WHERE.

Por exemplo, você tem A.ItemNum = B.ItemNum E B.ItemNum = C.ItemNum. Tente adicionar A.ItemNum = C.ItemNum também. Tenho certeza, porém, que o otimizador é suficiente inteligente para descobrir isso por conta própria -. Vale a pena tentar embora

Dependendo do tipo de dados da coluna ItemType pode ocorrer mais rápido execução utilizando o seguinte se é um varchar, a Oracle vai fazer conversões implict.

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC

Tem estatísticas recolhidas sobre essas tabelas? Se não, reunindo estatísticas pode alterar o plano de execução, ainda que não seria necessariamente para melhor.

Além de que, olhar para o plano de execução. Pode ver-se que une as tabelas em uma ordem não-óptima (por exemplo, pode-se juntar b e c antes de se juntar com uma que tem a condição do filtro).

Você pode usar as dicas para tentar afetar os caminhos de acesso, ordem de junção, ou juntar método.

Atualizar : Respondendo ao comentário levou-me a este apresentação, que pode ser útil ou pelo menos interessante.

Se você disser que não há índices, em seguida, que isso também significa que não há chaves primárias ou estrangeiras definidas? Obviamente analisando as tabelas e coleta estatísticas são importantes, mas se metadados, como a definição de como as tabelas devem ser unidas não existe, o Oracle pode muito bem escolher um caminho de execução pobre.

Nesse caso, utilizando uma dica como / * + ORDERED * / pode muito bem ser a única opção para fazer o otimizador escolher de forma confiável um caminho boa execução. Ele também pode valer a pena acrescentar chaves estrangeiras e chaves primárias, mas defini-los como DISABLE e validar.

Eu acho que a utilidade deste comentário depende de quão longe a aversão a índices vai tão YMMV.

Primeiro crie um ponto de vista sobre esta consulta e, em seguida, gerar uma tabela a partir deste ponto de vista. Também criar um índice na data, fazer um trabalho e programá-lo no tempo meia-noite quando o sistema estiver ocioso.

Bem, desde que você não pode criar índices, eu tinha certeza que as estatísticas são up-to-date, em seguida, eu reescrever a consulta desta forma:

with a as (select /*+ MATERIALIZE */ ItemType, ItemNum, DateStored, ItemDate from items where ItemType in (112,115,189,241)) SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath FROM a, itempages b, keygroupdata c WHERE a.ItemNum = b.ItemNum AND b.ItemNum = c.ItemNum ORDER BY a.DateStored DESC

Remova o ORDER BY

executar a classificação, depois de puxar as linhas de volta para sua aplicação.

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