ДЕЙСТВИТЕЛЬНО ли возможно, что порядок для этой конкретной избыточной производной таблицы не будет гарантирован?

12

Я наткнулся на этот вопрос в беседе в Твиттере с Лукасом Эдером .

Хотя правильное поведение будет заключаться в применении предложения ORDER BY к самому внешнему запросу, поскольку здесь мы не используем DISTINCT, GROUP BY, JOIN или любое другое предложение WHERE в самом внешнем запросе, почему бы СУРБД просто не передать входящие данные как они были отсортированы по внутреннему запросу?

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

При запуске этого примера на PostgreSQL, по крайней мере, вы получаете один и тот же план выполнения как для внутреннего запроса, так и для этого примера производной таблицы, а также один и тот же набор результатов.

Итак, я предполагаю, что планировщик просто отбросит самый внешний запрос, потому что он избыточен, или просто пропустит результаты из внутренней таблицы.

Кто-нибудь думает, что это может быть не так?

Влад Михалча
источник
4
Обратите внимание, что ваш запрос не удастся выполнить в SQL Server, так как в производной таблице не разрешен порядок по.
a_horse_with_no_name
Почему ты такой недоверчивый? Зачем ты что-то предполагал? Когда вы пишете программу, которая оставляет вам выбор, ожидаете ли вы, что пользователи будут ожидать чего-то от вашего выбора? Прочитайте об оптимизации и реализации логических и физических запросов.
Philipxy
2
«Я бы предположил, что планировщик просто отбросит самый внешний запрос, потому что он избыточен, или просто пропустит результаты из внутренней таблицы». Вы также можете легко предположить, что Планировщик отбросит предложение об упорядочении во внутреннем запросе, поскольку оно бессмысленно в контексте.
Wildcard
MariaDB, около 2012 года, обсуждает эту проблему. Отсутствие внутреннегоORDER BYприводит к различной оптимизации для групповых макс .
Рик Джеймс
1
На самом деле, вы правы для Postgres.
Эрвин Брандштеттер

Ответы:

20

Большинство баз данных совершенно ясно понимают, что ORDER BYподзапрос - это либо:

  • Недопустимо: например, SQL Server, Sybase SQL Anywhere (если не дополнено TOPили OFFSET .. FETCH)
  • Бессмысленно: например, PostgreSQL, DB2 (опять же, если не дополнено OFFSET .. FETCHили LIMIT)

Вот пример из руководства по DB2 LUW (выделено мое)

Предложение ORDER BY в подвыборке не влияет на порядок строк, возвращаемых запросом. Предложение ORDER BY влияет только на порядок возвращаемых строк, если оно указано во внешней полной выборке.

Формулировка довольно четкая, как и в PostgreSQL :

Если сортировка не выбрана, строки будут возвращены в неуказанном порядке. Фактический порядок в этом случае будет зависеть от типов планов сканирования и соединения и порядка на диске, но на него нельзя полагаться . Конкретный порядок вывода может быть гарантирован, только если шаг сортировки выбран явно.

Из этой спецификации следует, что любой порядок, полученный в результате ORDER BYпредложения в производной таблице, является просто случайным и может совпадать с вашим ожидаемым порядком (что он делает в большинстве баз данных в вашем тривиальном примере), но было бы неразумно полагаться на это.

Дополнительное примечание по DB2:

В частности, DB2 имеет менее известную функцию под названиемORDER BY ORDER OF <table-designator> , которая может использоваться следующим образом:

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

В этом конкретном случае упорядочение производной таблицы может быть явно использовано повторно во внешнем SELECT

Дополнительное примечание по Oracle:

В течение многих лет в Oracle практикуется использование OFFSETразбиения на страницы ROWNUM, которое может быть разумно рассчитано только после заказа производной таблицы:

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

Можно разумно ожидать, что, по крайней мере, при наличии ROWNUMв запросе будущие версии Oracle не будут нарушать это поведение, чтобы не сломать практически весь существующий Oracle SQL, который еще не перешел на гораздо более желательный и читаемый стандартный OFFSET .. FETCHсинтаксис SQL :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
Лукас Эдер
источник
Meaningless: E.g. PostgreSQLдействительно должно быть: «ненадежным», потому что это что-то значит. Строки сортируются во внутреннем запросе, и этот порядок сохраняется на внешних уровнях запроса, если не указано иное, или переупорядочение не подходит для дополнительных операций. Даже если это просто деталь реализации, это не бессмысленно. Это можно использовать для отсортированного ввода в агрегатные функции. Руководство даже намекает так много: Alternatively, supplying the input values from a sorted subquery will usually work.
Эрвин Брандштеттер
Цитата, которую вы добавили для Postgres, фактически относится к другому случаю: к запросам вообще нет ORDER BY.
Эрвин Брандштеттер
@ErwinBrandstetter: не стесняйтесь добавлять ответ с этими деталями. Я лично не согласен с тем, что детали реализации имеют смысл. Только сегодня я узнал, что в старые времена люди полагались на то, что Oracle всегда выполнял отсортированную группу с помощью операции в Oracle 8i (я полагаю), когда внезапно более новая версия представила хешированную группу by, что сломало предположение, что некоторые неявные на порядок можно положиться. Другими словами: я хотел бы выразить это смелыми словами. Бессмысленно , а не о, если вы знаете сложные детали версии xyz, вы можете на самом деле ...
Лукас Эдер
Я уже добавил ответ. Независимо от того, решили ли мы игнорировать нестандартное поведение или какие еще полезные советы мы получили, у нас есть вопрос: гарантирован ли порядок для данного запроса? Это для Postgres. Это не (или даже не применимо) для других RDBMS. И это относится ко всем существующим версиям Postgres, а не только к версии xyz. Это даже задокументировано (с оговорками). Ваша цитата вводит в заблуждение. Если мы хотим игнорировать нестандартное поведение, мы можем начать с Oracle, заставляя нас верить, что NULL и пустая строка одинаковы. Также ортогонально к вопросу.
Эрвин Брандштеттер,
@ErwinBrandstetter: Интересно, спасибо за обновление. Это гарантия того, что вы имеете в виду документально?
Лукас Эдер
12

Да. Без ORDER BYпредложения порядок вывода не определен, и планировщик запросов вполне может предположить, что вы это знаете и понимаете.

Он может решить, что, поскольку внешний запрос не определяет порядок, он может отбросить порядок во внутреннем запросе, чтобы избежать операции сортировки, особенно если нет кластерного индекса или индекса вообще, чтобы поддерживать порядок. Если этого не произойдет сейчас, это может быть сделано в будущих версиях.

Никогда не полагайтесь на неопределенное поведение. Если вам нужен конкретный заказ, дайте ORDER BYпункт в соответствующем месте.

Дэвид Спиллетт
источник
При тестировании на PostgreSQL сортировка выполнялась после последовательного сканирования, поскольку у меня не было индекса для столбца, используемого ORDER BY. Как вы думаете, какая СУБД пропустит внутренний запрос ORDER BY?
Влад Михалча
5
Я не могу сказать, что знаю, что будет , только то, что все они совершенно свободны, если захотят - это будет вполне приемлемая оптимизация в соответствии как с общими стандартами, так и со спецификациями продукта. SQL Server будет отклонять запрос напрямую (если вы не включите его, TOP 100%чтобы текущий запрос не был переносимым, если это будет приоритетом для вашего проекта. Поскольку Postgres подчиняется порядку во внутреннем запросе сейчас, это не означает, что это всегда будет происходить в будущем (или что на самом деле старые версии), поэтому вы должны избегать полагаться на поведение на всякий случай
Дэвид
1
@VladMihalcea СУБД, которая «оптимизирует» избыточность, ORDER BYявляется MariaDB: почему ORDER BY в подзапросе FROM игнорируется?
ypercubeᵀᴹ
6

Сама проблема с неопределенным поведением - работает для вас, работает для меня, переформатирует жесткий диск в prod;)

Мы можем сделать шаг назад и сказать, что в каком-то смысле вы правы - нет никаких земных причин, по которым любая здравомыслящая СУБД будет переставлять строки во внутреннем выборе. Но это не гарантировано - это означает, что в будущем может быть причина, и поставщики могут это сделать. Это означает, что любой код, основанный на этом поведении, зависит от изменений, которые может сделать поставщик, и которые он не обязан публиковать, поскольку это не является принципиальным изменением от API POV.

PaulJWilliams
источник
2
Единственная причина, по которой он может оптимизировать заказ - это скорость. Возвращение строк в другом порядке может быть более эффективным.
TomTom
2
В частности, сервер может использовать параллелизм для чтения таблицы. Если это так, и нет необходимости применять порядок, вы получите строки обратно, как бы их ни читали потоки. (SQL Server фактически делает это, так что « SELECTбез» ORDER BYдействительно недетерминировано, и не только в теории или потому, что данные изменились.)
Йерун Мостерт
@JeroenMostert: неопределенное поведение только ухудшается. Что произойдет, если он выйдет из строя и дельта будет использована для индексации в массив?
Джошуа
2

ДЕЙСТВИТЕЛЬНО ли возможно, что порядок для этой конкретной избыточной производной таблицы не будет гарантирован?

Ответ для всех существующих на данный момент версий Postgres (которые вы тестировали): Нет - для этого конкретного запроса. Порядок сортировки гарантирован.

Людям на SQL-сервере это будет неудобно, поскольку Microsoft даже не допускает ORDER BYподзапросов. Тем не менее, порядок сортировки для этого простого запроса в Postgres гарантирован. ORDER BYприменяется в подзапросе, и внешний запрос не делает ничего, что могло бы изменить порядок.

Руководство даже намекает так много в главе Агрегатные функции :

Альтернативно, подача входных значений из отсортированного подзапроса обычно работает.

Обратите внимание, что это верно только тогда, когда внешние уровни запросов не добавляют операции, которые могут изменить порядок. Так что это «гарантировано» только для простого случая, и это не поддерживается стандартом SQL. Postgres может изменить порядок, если он подходит для дополнительных операций. В случае сомнений добавьте еще один ORDER BYк внешнему SELECT. (В этом случае внутренняя часть ORDER BYбудет лишним шумом для этого простого запроса.)

Эрвин Брандштеттер
источник
Верно ли, что "table"это не простая базовая таблица, а сложное представление или секционированная таблица? Верно ли и то, что план имеет параллельное исполнение? Это правда и в Postgres 10? (Я только спрашиваю, я не уверен в ответе на любой из этих вопросов.)
ypercubeᵀᴹ
@ ypercubeᵀᴹ: я не проверял Postgres 10 на все это, но я уверен, что это правда в любом случае. Порядок применяется и не изменяется во внешнем запросе для простого случая.
Эрвин Брандштеттер