Como posso acelerar row_number no Oracle?
-
05-07-2019 - |
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?
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):
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?