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?

¿Fue útil?

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):

Debes ordenar por algo exclusivo para estas consultas de paginación, por lo que ROW_NUMBER se asigna de forma determinista a las filas cada vez.

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?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top