web-dev-qa-db-fra.com

Est-il VRAIMENT possible que la commande ne soit pas garantie pour cette table dérivée redondante particulière?

Je suis tombé sur cette question sur un conversation Twitter avec Lukas Eder .

Bien que le comportement correct serait d'appliquer la clause ORDER BY à la requête la plus externe, car, ici, nous n'utilisons pas DISTINCT, GROUP BY, JOIN ou toute autre clause WHERE dans la requête la plus externe, pourquoi un SGBDR ne passerait-il pas simplement la les données entrantes telles qu'elles ont été triées par la requête interne?

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

Lorsque vous exécutez cet exemple sur PostgreSQL, au moins, vous obtenez le même plan d'exécution pour la requête interne et cet exemple de table dérivée, ainsi que le même jeu de résultats.

Donc, je suppose que le planificateur supprimera simplement la requête la plus externe car elle est redondante ou passera simplement par les résultats de la table interne.

Quelqu'un pense-t-il que ce n'est pas le cas?

12
Vlad Mihalcea

La plupart des bases de données sont assez claires sur le fait qu'un ORDER BY Dans une sous-requête est soit:

  • Non autorisé: par ex. SQL Server, Sybase SQL Anywhere (sauf si complété par TOP ou OFFSET .. FETCH)
  • Inutile: ex. PostgreSQL, DB2 (encore une fois, sauf si complété par OFFSET .. FETCH Ou LIMIT)

Voici un exemple tiré du manuel DB2 LUW (accent sur le mien)

Une clause ORDER BY dans une sous-sélection n'affecte pas l'ordre des lignes renvoyé par une requête. Une clause ORDER BY n'affecte l'ordre des lignes renvoyées que si elle est spécifiée dans le fullselect le plus externe.

La formulation est assez explicite, tout comme celle de PostgreSQL :

Si le tri n'est pas choisi, les lignes seront retournées dans un ordre non spécifié. L'ordre réel dans ce cas dépendra des types de plan d'analyse et de jointure et de l'ordre sur le disque, mais il ne faut pas s'y fier. Un ordre de sortie particulier ne peut être garanti que si l'étape de tri est explicitement choisie.

D'après cette spécification, il peut être suivi que tout ordre résultant de la clause ORDER BY Dans une table dérivée est simplement accidentel et peut coïncider par hasard avec votre ordre attendu (ce qu'il fait dans la plupart des bases de données dans votre exemple trivial), mais il il serait imprudent de s’y fier.

Note latérale sur DB2:

En particulier, DB2 a une fonction moins connue appelée ORDER BY ORDER OF <table-designator> , qui peut être utilisée comme suit:

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

Dans ce cas particulier, l'ordre de la table dérivée peut être explicitement réutilisé dans le plus externe SELECT

Note complémentaire sur Oracle:

Pendant des années, il a été une pratique dans Oracle pour implémenter OFFSET pagination en utilisant ROWNUM, qui peut être raisonnablement calculé uniquement après ordonnant une table dérivée:

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

On peut raisonnablement s'attendre à ce qu'au moins en présence de ROWNUM dans une requête, les futures versions d'Oracle ne brisent pas ce comportement afin de ne pas briser à peu près tout le SQL Oracle existant, qui n'a pas encore migré à la syntaxe SQL OFFSET .. FETCH SQL beaucoup plus souhaitable et lisible:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
20
Lukas Eder

Oui. Sans ORDER BY clause l'ordre de sortie n'est pas défini et le planificateur de requêtes est tout à fait à sa portée de supposer que vous le savez et le comprenez.

Il peut décider que parce que la requête externe ne spécifie pas d'ordre, il peut supprimer l'ordre dans la requête interne pour éviter une opération de tri, surtout s'il n'y a pas d'index cluster ou pas d'index du tout pour prendre en charge l'ordre. Si ce n'est pas le cas maintenant , cela pourrait le faire dans les futures versions.

Ne vous fiez jamais à un comportement indéfini. Si vous avez besoin d'une commande spécifique, donnez un ORDER BY clause à l'endroit approprié.

12
David Spillett

C'est le problème même avec un comportement indéfini - fonctionne pour vous, fonctionne pour moi, reformate le disque dur en prod;)

Nous pouvons prendre du recul et dire que dans un sens, vous avez raison - il n'y a aucune raison terrestre pour laquelle un SGBDR sensé réorganiserait les lignes dans la sélection intérieure. Mais ce n'est pas garanti - ce qui signifie qu'il peut y avoir à l'avenir une raison, et les vendeurs sont libres de le faire. Cela signifie que tout code qui s'appuie sur ce comportement est à la merci d'un changement qu'un fournisseur pourrait apporter et qu'il n'aurait aucune obligation de publier, car il ne s'agit pas d'un changement de rupture par rapport à un PDV API.

6
PaulJWilliams

Est-il VRAIMENT possible que la commande ne soit pas garantie pour cette table dérivée redondante particulière?

La réponse pour toutes les versions Postgres (que vous testiez) actuellement existantes est: Non - pour cette requête particulière. L'ordre de tri est garanti.

Les gens du serveur SQL ne seront pas à l'aise avec cela car Microsoft n'autorise même pas ORDER BY Dans les sous-requêtes. L'ordre de tri est néanmoins garanti pour cette simple requête dans Postgres. ORDER BY Est appliqué dans la sous-requête et la requête externe ne fait rien qui puisse changer l'ordre.

Le manuel l'indique même dans le chapitre Fonctions d'agrégation:

Alternativement, la fourniture des valeurs d'entrée à partir d'une sous-requête triée fonctionne généralement.

Notez que cela n'est vrai que lorsque les niveaux de requête externes n'ajoutent pas d'opérations susceptibles de modifier l'ordre. Il n'est donc "garanti" que pour le cas simple, et ce n'est pas soutenu par la norme SQL. Postgres est libre de réorganiser si cela est opportun pour des opérations supplémentaires. En cas de doute, ajoutez un autre ORDER BY Au SELECT extérieur. (Dans ce cas, le ORDER BY Interne serait un bruit redondant pour cette simple requête.)

2
Erwin Brandstetter