Pergunta

Eu tenho uma consulta SQL que é algo como isto:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

Essencialmente, é o ORDER BY parte que está abrandar as coisas. Se eu fosse para removê-lo, o EXPLICAR custo vai para baixo por uma ordem de magnitude (mais de 1000x). Eu tentei isso:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

Mas isso não dá resultados corretos. Existe alguma maneira fácil de acelerar isso? Ou terei de passar mais algum tempo com a ferramenta explicar?

Foi útil?

Solução

ROW_NUMBER é bastante ineficiente em Oracle.

Veja o artigo no meu blog para mais detalhes de desempenho:

Para a sua consulta específica, eu recomendo que você substituí-lo por ROWNUM e certifique-se que o índice é usado:

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

Esta consulta vai usar COUNT STOPKEY

Além disso, quer a certeza que não column é anulável, ou adicionar condição WHERE column IS NOT NULL.

Caso contrário, o índice não pode ser usado para recuperar todos os valores.

Note que você não pode usar ROWNUM BETWEEN :start and :end sem uma subconsulta.

ROWNUM é sempre atribuído passado e verificado passado, que de maneira ROWNUM sempre vêm em ordem sem lacunas.

Se você usar ROWNUM BETWEEN 10 and 20, a primeira linha que satisifies todas as outras condições se tornará um candidato para o regresso, temporariamente atribuído com ROWNUM = 1 e falhar no teste de ROWNUM BETWEEN 10 AND 20.

Em seguida, a próxima linha será um candidato, atribuído com ROWNUM = 1 e falhar, etc., de modo que, finalmente, nenhuma linha será devolvido em tudo.

Isto deve ser contornado, colocando ROWNUM de dentro da subconsulta.

Outras dicas

parece uma consulta de paginação para mim.

A partir deste artigo AskTom (cerca de 90% abaixo da página):

Você precisa fim por algo única para essas consultas de paginação, para que ROW_NUMBER é atribuído de forma determinística para as fileiras cada vez.

Também suas consultas não são onde perto do mesmo, então eu não sei o que o benefício de comparar os custos de um para o outro é.

é seu ORDER BY coluna indexada? Se não for isso é um bom lugar para começar.

Parte do problema é o quão grande é o 'start' para extensão 'fim' e onde 'ao vivo'. Digamos que você tenha um milhão de linhas na tabela, e você quer linhas 567.890 para 567.900, em seguida, você vai ter que viver com o fato de que ele está indo para necessidade de passar por toda a tabela, tipo praticamente todos que por id, e trabalhar para fora o que linhas se enquadram nessa faixa.

Em suma, isso é um monte de trabalho, razão pela qual o otimizador lhe confere um alto custo.

Ele também não é algo que um índice pode ajudar com muito. Um índice daria a ordem, mas na melhor das hipóteses, que lhe dá um lugar para começar e então você manter a leitura em até chegar à entrada 567900.

Se você está mostrando o seu usuário final 10 itens de uma vez, pode valer a pena realmente pegar o top 100 da DB, em seguida, tendo a quebra aplicativo que 100 em dez pedaços.

Passe mais tempo com a ferramenta de plano de explicação. Se você ver uma varredura na tabela que você precisa para alterar a sua consulta.

A sua consulta não faz muito sentido para mim. Consultando ao longo de um ROWID parece pedindo para ter problemas. Não há nenhuma informação relacional em que consulta. É a consulta real que você está tendo problemas com ou um exemplo que você fez-se para ilustrar o seu problema?

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