Недавно я объяснял коллегам важность наличия столбца, по которому можно сортировать данные в таблице базы данных, если это необходимо, например, для хронологически упорядоченных данных. Это оказалось несколько сложным, потому что они могли просто повторять свой запрос, казалось бы, бесконечно, и он всегда возвращал бы один и тот же набор строк в одном и том же порядке.
Я заметил это раньше, и все, что я мог на самом деле сделать, - это настаивать, чтобы они доверяли мне, а не просто предполагали, что таблица базы данных будет вести себя как традиционный файл CSV или Excel.
Например, выполнение запроса (PostgreSQL)
create table mytable (
id INTEGER PRIMARY KEY,
data TEXT
);
INSERT INTO mytable VALUES
(0, 'a'),
(1, 'b'),
(2, 'c'),
(3, 'd'),
(4, 'e'),
(5, 'f'),
(6, 'g'),
(7, 'h'),
(8, 'i'),
(9, 'j');
создаст таблицу с четким концептуальным порядком. Выбор этих же данных самым простым способом будет:
SELECT * FROM mytable;
Всегда дает мне следующие результаты:
id | data
----+------
0 | a
1 | b
2 | c
3 | d
4 | e
5 | f
6 | g
7 | h
8 | i
9 | j
(10 rows)
Я могу делать это снова и снова, и он всегда будет возвращать мне одни и те же данные в одном и том же порядке. Однако я знаю, что этот неявный порядок может быть нарушен, я видел его раньше, особенно в больших наборах данных, где некоторое случайное значение, по-видимому, будет выброшено в «неправильное» место при выборе. Но мне пришло в голову, что я не знаю, как это происходит или как это воспроизвести. Мне трудно получить результаты в Google, потому что поисковый запрос имеет тенденцию просто возвращать общую справку по сортировке наборов результатов.
Итак, мои вопросы по сути следующие:
Как я могу наглядно и конкретно доказать, что порядок возврата строк в запросе без
ORDER BY
оператора ненадежен, предпочтительно, вызывая и показывая разбивку неявного порядка, даже если рассматриваемая таблица не обновляется и не редактируется ?Имеет ли это какое-то значение, если данные вводятся только один раз, а затем никогда не обновляются?
Я бы предпочел ответ на основе postgres, поскольку он мне наиболее знаком, но меня больше интересует сама теория.
order by
пункта в свои запросы? Они пытаются сэкономить на хранении исходного кода? износ клавиатуры? время, необходимое для ввода страшного предложения?Ответы:
Я вижу три способа убедить их:
Пусть они попробуют тот же запрос, но с большей таблицей (с большим количеством строк) или когда таблица обновляется между выполнениями. Или новые строки вставляются, а некоторые старые удаляются. Или индекс добавляется или удаляется между выполнениями. Или стол пылесосится (в Postgres). Или индексы перестраиваются (в SQL Server). Или таблица меняется с кластерной на кучу. Или служба базы данных перезапущена.
Вы можете предложить им доказать, что разные казни будут возвращать один и тот же порядок. Могут ли они доказать это? Могут ли они предоставить серию тестов, доказывающих, что любой запрос даст результат в одном и том же порядке, независимо от того, сколько раз он выполняется?
Предоставить документацию по различным СУБД. Например:
PostgreSQL :
SQL Server :
Оракул :
источник
ORDER BY
, которое будет гарантировать порядок, независимо от того, как будет меняться стол ? Почему бы не добавить сейф, который не причиняет вреда?Это история черного лебедя снова и снова. Если вы еще не видели, это не значит, что они не существуют. Надеемся, что в вашем случае это не приведет к еще одному мировому финансовому кризису, просто к нескольким недовольным клиентам.
Документация Postgres говорит об этом явно:
«Система» в данном случае включает в себя сам демон postgres (включая реализацию его методов доступа к данным и оптимизатор запросов), базовую операционную систему, логическую и физическую структуру хранилища базы данных, возможно, даже кэши ЦП. Поскольку вы, как пользователь базы данных, не имеете никакого контроля над этим стеком, вы не должны полагаться на то, что он продолжает вести себя вечно так, как он ведет себя в эту самую минуту.
Ваши коллеги совершают поспешную ошибку обобщения . Чтобы опровергнуть их точку зрения, достаточно показать, что их допущение неверно только один раз, например, этим dbfiddle .
источник
Рассмотрим следующий пример, где у нас есть три связанных таблицы. Заказы, пользователи и детали заказа. OrderDetails связан с внешними ключами для таблицы Orders и таблицы Users. По сути, это очень типичная установка для реляционных баз данных; возможно вся цель реляционной СУБД.
Здесь мы запрашиваем таблицу OrderDetails, где UserID равен 15:
Вывод запроса выглядит следующим образом:
Как видите, порядок вывода строк не соответствует порядку строк в таблице OrderDetails.
Добавление явного
ORDER BY
гарантирует, что строки будут возвращены клиенту в желаемом порядке:Если порядок строк является обязательным, и ваши инженеры знают, что порядок является обязательным, им следует только захотеть использовать
ORDER BY
оператор, так как это может стоить им назначения, если произошла ошибка, связанная с неправильным порядком.Во втором, возможно, более поучительном примере, используя
OrderDetails
приведенную выше таблицу, где мы не объединяем никакие другие таблицы, но имеем простое требование найти строки, соответствующие как OrderID, так и UserID, мы видим проблему.Мы создадим индекс для поддержки запроса, как вы, вероятно, сделали бы в реальной жизни, если производительность имеет какое-либо значение (когда это не так?).
Вот запрос:
И результаты:
Добавление
ORDER BY
предложения определенно гарантирует, что и здесь мы получим правильную сортировку.Эти макеты являются просто простыми примерами, где строки не могут быть «в порядке» без явного
ORDER BY
утверждения. Подобных примеров гораздо больше, и поскольку код механизма СУБД меняется довольно часто, конкретное поведение может со временем меняться.источник
В качестве практического примера, в Postgres, порядок в данный момент изменяется при обновлении строки:
Я не думаю, что правила этого существующего неявного упорядочения где-либо задокументированы, определенно могут быть изменены без предварительного уведомления, и, безусловно, не переносимы в ядрах БД.
источник
не совсем демо, но слишком долго для комментария.
В больших таблицах некоторые базы данных будут выполнять чередующиеся параллельные сканирования:
Если два запроса хотят отсканировать одну и ту же таблицу и поступить почти одновременно, первый может быть частично пройден через таблицу при запуске второго.
Второй запрос может получать записи, начиная с середины таблицы (когда первый запрос завершается), а затем получать записи из начала таблицы.
источник
Создайте кластерный индекс, который имеет «неправильный» порядок. Например, кластер на
ID DESC
. Это часто выводит обратный порядок (хотя это также не гарантируется).источник