¿Cómo puedo acelerar el número de fila en Oracle?
-
05-07-2019 - |
Pregunta
Tengo una consulta SQL que se parece a esto:
SELECT * FROM(
SELECT
...,
row_number() OVER(ORDER BY ID) rn
FROM
...
) WHERE rn between :start and :end
Esencialmente, es la parte ORDENAR que ralentiza las cosas. Si tuviera que eliminarlo, el costo de EXPLAIN se reducirá en un orden de magnitud (más de 1000x). He intentado esto:
SELECT
...
FROM
...
WHERE
rownum between :start and :end
Pero esto no da resultados correctos. ¿Hay alguna manera fácil de acelerar esto? ¿O tendré que pasar más tiempo con la herramienta EXPLAIN?
Solución
ROW_NUMBER
es bastante ineficiente en Oracle
.
Consulte el artículo en mi blog para obtener detalles sobre el rendimiento:
Para su consulta específica, le recomiendo que lo reemplace con ROWNUM
y asegúrese de que se use el índice:
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 utilizará COUNT STOPKEY
También asegúrese de que la columna
no sea anulable, o agregue la condición DONDE LA columna NO ES NULA
.
De lo contrario, el índice no se puede utilizar para recuperar todos los valores.
Tenga en cuenta que no puede usar ROWNUM ENTRE: start y: end
sin una subconsulta.
ROWNUM
siempre se asigna en último lugar y se comprueba en último lugar, así es como ROWNUM
siempre se pone en orden sin espacios.
Si utiliza ROWNUM ENTRE 10 y 20
, la primera fila que satisfaga todas las demás condiciones se convertirá en una candidata para regresar, asignada temporalmente con ROWNUM = 1
y no podrá prueba de ROWNUM ENTRE 10 Y 20
.
Entonces, la siguiente fila será candidata, asignada con ROWNUM = 1
y fallará, etc., por lo que, finalmente, no se devolverán filas en absoluto.
Esto debería solucionarse poniendo las ROWNUM
en la subconsulta.
Otros consejos
A mí me parece una consulta de paginación.
De este artículo de ASKTOM (alrededor del 90% en la página):
Además, sus consultas no son iguales, así que no estoy seguro de cuál es el beneficio de comparar los costos de uno con el otro.
¿Su columna ORDER BY está indexada? Si no, ese es un buen lugar para comenzar.
Parte del problema es qué tan grande es el lapso de 'inicio' a 'final' y dónde 'viven'. Digamos que tienes un millón de filas en la tabla y quieres las filas 567,890 a 567,900, entonces tendrás que vivir con el hecho de que va a tener que pasar por toda la tabla, ordenar casi todo eso por id, y averiguar qué filas caen en ese rango.
En resumen, eso es mucho trabajo, por lo que el optimizador le da un alto costo.
Tampoco es algo que un índice pueda ayudar con mucho. Un índice daría el orden, pero en el mejor de los casos, eso te da un punto de partida y luego sigues leyendo hasta que llegas a la entrada 567.900.
Si le está mostrando 10 elementos a su usuario final a la vez, puede que valga la pena obtener los 100 principales de la base de datos y luego hacer que la aplicación rompa 100 en diez partes.
Pase más tiempo con la herramienta EXPLAIN PLAN. Si ve una TABLA DE EXPLORACIÓN debe cambiar su consulta.
Tu consulta tiene poco sentido para mí. Preguntar por un ROWID parece pedir problemas. No hay información relacional en esa consulta. ¿Es la consulta real con la que tiene problemas o un ejemplo que inventó para ilustrar su problema?