¿Es REALMENTE posible que el pedido no esté garantizado para esta tabla derivada redundante en particular?

12

Me topé con esta pregunta en una conversación de Twitter con Lukas Eder .

Aunque el comportamiento correcto sería aplicar la cláusula ORDER BY en la consulta más externa, porque, aquí, no estamos utilizando DISTINCT, GROUP BY, JOIN o cualquier otra cláusula WHERE en la consulta más externa, ¿por qué un RDBMS no pasaría la datos entrantes como fueron ordenados por la consulta interna?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

Al ejecutar este ejemplo en PostgreSQL, al menos, obtiene el mismo Plan de ejecución para la consulta interna y este ejemplo de tabla derivada, así como el mismo conjunto de resultados.

Entonces, supongo que el Planificador simplemente descartará la consulta más externa porque es redundante o simplemente pasará los resultados de la tabla interna.

¿Alguien piensa que este podría no ser el caso?

Vlad Mihalcea
fuente
44
Tenga en cuenta que su consulta fallará en SQL Server porque no se permite ordenar por dentro de una tabla derivada.
a_horse_with_no_name
¿Por qué eres tan incrédulo? ¿Por qué asumirías algo? Cuando escribe un programa que le deja una opción, ¿espera que los usuarios esperen cosas sobre su elección? Lea sobre la optimización / implementación de consultas lógicas y físicas.
philipxy
2
"Supongo que el Planificador simplemente descartará la consulta más externa porque es redundante o simplemente pasará los resultados de la tabla interna". Podría suponer fácilmente que el Planificador descartará la cláusula de ordenación en la consulta interna porque no tiene sentido en su contexto.
Comodín el
MariaDB, sobre 2012, discute el tema. La falta delORDER BYcableinternoa una optimización diferente para groupwise max .
Rick James el
1
En realidad, tienes razón para Postgres.
Erwin Brandstetter

Respuestas:

20

La mayoría de las bases de datos son bastante claras sobre el hecho de que un ORDER BYen una subconsulta es:

  • No permitido: por ejemplo, SQL Server, Sybase SQL Anywhere (a menos que se complemente con TOPo OFFSET .. FETCH)
  • Sin sentido: por ejemplo, PostgreSQL, DB2 (de nuevo, a menos que se complemente con OFFSET .. FETCHo LIMIT)

Aquí hay un ejemplo del manual de DB2 LUW (énfasis mío)

Una cláusula ORDER BY en una subselección no afecta el orden de las filas devueltas por una consulta. Una cláusula ORDER BY solo afecta el orden de las filas devueltas si se especifica en la selección completa más externa.

La redacción es bastante explícita, al igual que PostgreSQL :

Si no se elige la ordenación, las filas se devolverán en un orden no especificado. El orden real en ese caso dependerá de los tipos de plan de escaneo y unión y el orden en el disco, pero no se debe confiar en él . Un pedido de salida particular solo puede garantizarse si el paso de clasificación se elige explícitamente.

A partir de esta especificación, se puede seguir que cualquier orden resultante de la ORDER BYcláusula en una tabla derivada es meramente accidental y puede coincidir coincidentemente con su orden esperado (lo que hace en la mayoría de las bases de datos en su ejemplo trivial), pero sería imprudente confiar en esta.

Nota al margen sobre DB2:

En particular, DB2 tiene una característica menos conocida llamadaORDER BY ORDER OF <table-designator> , que se puede utilizar de la siguiente manera:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

En este caso particular, el orden de la tabla derivada se puede reutilizar explícitamente en el exterior más SELECCIONAR

Nota al margen sobre Oracle:

Durante años ha sido una práctica en Oracle implementar el OFFSETuso de la paginación ROWNUM, que puede calcularse razonablemente solo después de ordenar una tabla derivada:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

Se puede esperar razonablemente que, al menos en presencia de ROWNUMuna consulta, las futuras versiones de Oracle no rompan este comportamiento para no romper casi todo el Oracle SQL heredado que aún no se ha migrado a los más deseables y deseados. OFFSET .. FETCHsintaxis estándar de SQL legible :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
Lukas Eder
fuente
Meaningless: E.g. PostgreSQLen realidad debería ser: 'poco fiables', ya que lo hace significar algo. Las filas se ordenan en la consulta interna, y ese orden se mantiene en los niveles de la consulta externa, a menos que se indique lo contrario o el reordenamiento sea oportuno para operaciones adicionales. Incluso si eso es solo un detalle de implementación, no tiene sentido. Esto se puede usar para entradas ordenadas para agregar funciones. El manual incluso da pistas: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter
La cita que agregó para Postgres en realidad se aplica a un caso diferente: consultas sin ninguna ORDER BY.
Erwin Brandstetter
@ErwinBrandstetter: siéntase libre de agregar una respuesta con esos detalles. Personalmente, no estoy de acuerdo con que los detalles de implementación sean significativos. Justo hoy, he aprendido que en los viejos tiempos, la gente confiaba en que Oracle siempre realizaba un grupo ordenado por operación en Oracle 8i (creo), cuando de repente, una versión más nueva introdujo el grupo hash, lo que rompió la suposición de que algunos implícitos se puede confiar en el pedido. En otras palabras: me gusta ponerlo en negrita. Sin sentido , en lugar de oh si conoces los intrincados detalles de la versión xyz, en realidad puedes ...
Lukas Eder
Ya agregué una respuesta. Si optamos por ignorar el comportamiento no estándar o qué otro buen consejo tenemos al lado de la pregunta: ¿Se garantiza el orden para la consulta dada? Es para Postgres. No es (o ni siquiera aplicable) para otros RDBMS. Y eso se aplica a todas las versiones existentes de Postgres, no solo a la versión xyz. Incluso está documentado (con reservas). Su cita es engañosa. Si queremos ignorar el comportamiento no estándar, podríamos comenzar con Oracle haciéndonos creer que NULL y la cadena vacía son lo mismo. También ortogonal a la pregunta.
Erwin Brandstetter
@ErwinBrandstetter: Interesante, gracias por la actualización. ¿Es esta garantía a la que te refieres documentado?
Lukas Eder
12

Si. Sin una ORDER BYcláusula, el orden de salida no está definido y el planificador de consultas está dentro de su alcance para asumir que usted lo sabe y lo comprende.

Puede decidir que debido a que la consulta externa no especifica un orden, puede descartar el orden en la consulta interna para evitar una operación de clasificación, especialmente si no hay un índice agrupado o ningún índice para admitir el orden. Si no lo hace ahora , puede hacerlo en futuras versiones.

Nunca confíes en un comportamiento indefinido. Si necesita un pedido específico, proporcione una ORDER BYcláusula en el lugar apropiado.

David Spillett
fuente
Al probarlo en PostgreSQL, la clasificación se realizó después de una exploración secuencial, ya que no tenía ningún índice en la columna utilizada por ORDER BY. ¿Qué RDBMS crees que saltará la consulta interna ORDER BY?
Vlad Mihalcea
55
No puedo decir que sé lo que cualquier voluntad , sólo que cualquiera y todos son perfectamente libre de hacerlo si así lo desean - que sería una optimización perfectamente aceptable de acuerdo tanto a las normas generales y las especificaciones del producto. SQL Server rechazará la consulta directamente (a menos que la incluya TOP 100%para que la consulta actual no sea portátil, si esa es una prioridad para su proyecto. Dado que Postgres obedece el pedido en la consulta interna ahora, no implica que siempre lo hará en el futuro (o que las versiones anteriores hacen, de hecho) por lo que debe evitar depender de la conducta por si acaso.
David Spillett
1
@VladMihalcea un DBMS que "optimiza" el redundante ORDER BYes MariaDB: ¿Por qué se ignora ORDER BY en una subconsulta FROM?
ypercubeᵀᴹ
6

Es el problema con el comportamiento indefinido: funciona para usted, funciona para mí, formatea el HDD en prod;)

Podemos dar un paso atrás y decir que, en cierto sentido, tiene razón: no hay ninguna razón terrenal por la que un RDBMS sensato reorganice las filas en la selección interna. Pero no está garantizado, lo que significa que en el futuro puede haber una razón, y los proveedores son libres de hacerlo. Lo que significa que cualquier código que se base en este comportamiento está a merced de un cambio que un proveedor podría hacer y que no estaría obligado a publicar, ya que no es un cambio importante de un POV API.

PaulJWilliams
fuente
2
La única razón por la que puede optimizar el pedido es la velocidad. Devolver las filas en un orden diferente puede ser más eficiente.
TomTom
2
En particular, el servidor puede explotar el paralelismo para leer la tabla. Si lo hace, y no hay necesidad de hacer cumplir un pedido, obtendrá las filas de nuevo, sin embargo, los hilos las leen. (SQL Server realmente hace esto, de modo que una SELECTsin la ORDER BYverdad es no determinista, y no sólo en teoría o porque los datos cambiados.)
Jeroen Mostert
@JeroenMostert: el comportamiento indefinido solo empeora. ¿Qué sucede si está fuera de servicio y el delta se utilizó para indexar en una matriz?
Joshua
2

¿Es REALMENTE posible que el pedido no esté garantizado para esta tabla derivada redundante en particular?

La respuesta para todas las versiones existentes de Postgres (que estaba probando) es: No , para esta consulta en particular. El orden de clasificación está garantizado.

La gente del servidor SQL se sentirá incómoda con esto ya que Microsoft ni siquiera permite ORDER BYsubconsultas. No obstante, el orden de clasificación está garantizado para esta consulta simple en Postgres. ORDER BYse aplica en la subconsulta y la consulta externa no hace nada que pueda cambiar el orden.

El manual incluso lo insinúa en el capítulo Funciones agregadas :

Alternativamente, el suministro de los valores de entrada de una subconsulta ordenada generalmente funcionará.

Tenga en cuenta que esto solo es cierto mientras que los niveles de consulta externos no agregan operaciones que puedan cambiar el orden. Por lo tanto, solo está "garantizado" para el caso simple, y eso no está respaldado por el estándar SQL. Postgres es libre de reordenar si es oportuno para operaciones adicionales. En caso de duda agregue otro ORDER BYal exterior SELECT. (En cuyo caso, el ORDER BYruido interno sería redundante para esta simple consulta).

Erwin Brandstetter
fuente
¿Es cierto cuando "table"no se trata de una tabla básica simple sino de una vista compleja o una tabla particionada? ¿Es cierto cuando el plan también tiene ejecución paralela? ¿Es cierto también en Postgres 10? (Sólo te pido, no estoy seguro de la respuesta de cualquiera de estas preguntas.)
ypercubeᵀᴹ
@ ypercubeᵀᴹ: no he probado Postgres 10 para todos estos, pero estoy bastante seguro de que es cierto en cualquier caso. El orden se aplica y no se modifica en la consulta externa para el caso simple.
Erwin Brandstetter