Первое предложение Прадипа Адиги ORDER BY NEWID()
, хорошо, и то, что я использовал в прошлом по этой причине.
Будьте осторожны с использованием RAND()
- во многих контекстах он выполняется только один раз для каждого оператора, поэтому не ORDER BY RAND()
будет иметь никакого эффекта (поскольку вы получаете одинаковый результат из RAND () для каждой строки).
Например:
SELECT display_name, RAND() FROM tr_person
возвращает каждое имя из нашей таблицы персон и «случайное» число, которое одинаково для каждой строки. Число меняется каждый раз, когда вы запускаете запрос, но одинаково для каждой строки каждый раз.
Чтобы показать, что то же самое относится и к RAND()
используемому в ORDER BY
предложении, я пытаюсь:
SELECT display_name FROM tr_person ORDER BY RAND(), display_name
Результаты по-прежнему упорядочены по имени, указывающему, что более раннее поле сортировки (ожидаемое случайным образом) не имеет никакого эффекта, поэтому предположительно всегда имеет одинаковое значение.
Упорядочение по NEWID()
работает, хотя, потому что если бы NEWID () не всегда переоценивался, назначение UUID было бы нарушено при вставке множества новых строк в одно состояние с уникальными идентификаторами в качестве ключа, поэтому
SELECT display_name FROM tr_person ORDER BY NEWID()
делает заказ имен «случайные».
Другие СУБД
Вышесказанное верно для MSSQL (по крайней мере, 2005 и 2008, и, если я правильно помню, 2000). Функция, возвращающая новый UUID, должна оцениваться каждый раз во всех СУБД. NEWID () находится под MSSQL, но это стоит проверить в документации и / или в ваших собственных тестах. Поведение других функций с произвольным результатом, таких как RAND (), с большей вероятностью различается в разных СУБД, поэтому еще раз проверьте документацию.
Также я видел, как упорядочение по значениям UUID игнорируется в некоторых контекстах, поскольку БД предполагает, что тип не имеет значимого упорядочения. Если вы обнаружите, что это именно тот случай, явным образом приведите UUID к строковому типу в предложении упорядочения или оберните вокруг него какую-то другую функцию, как CHECKSUM()
в SQL Server (может также быть небольшое отличие в производительности, поскольку упорядочение будет выполнено на 32-битные значения, а не 128-битные, хотя перевесит ли выгода от этого затраты на запуск CHECKSUM()
одного значения, я оставлю вас на тестирование).
Примечание
Если вы хотите произвольное, но несколько повторяющееся упорядочение, упорядочите по некоторому относительно неконтролируемому подмножеству данных в самих строках. Например, либо они, либо они будут возвращать имена в произвольном, но повторяемом порядке:
SELECT display_name FROM tr_person ORDER BY CHECKSUM(display_name), display_name -- order by the checksum of some of the row's data
SELECT display_name FROM tr_person ORDER BY SUBSTRING(display_name, LEN(display_name)/2, 128) -- order by part of the name field, but not in any an obviously recognisable order)
Произвольные, но повторяемые порядки не часто полезны в приложениях, хотя могут быть полезны при тестировании, если вы хотите протестировать некоторый код на результатах в различных заказах, но хотите иметь возможность повторять каждый прогон несколько раз одинаково (для получения среднего времени результаты за несколько прогонов или тестирование того, что исправление, внесенное вами в код, устраняет проблему или неэффективность, ранее отмеченную определенным входным набором результатов, или просто для проверки того, что ваш код «стабилен», то есть каждый раз возвращает один и тот же результат если отправлены те же данные в заданном порядке).
Этот прием также можно использовать для получения более произвольных результатов от функций, которые не допускают недетерминированные вызовы, такие как NEWID (), в своем теле. Опять же, это не то, что может быть часто полезно в реальном мире, но может пригодиться, если вы хотите, чтобы функция возвращала что-то случайное, а «random-ish» достаточно хорошо (но будьте осторожны, чтобы запомнить правила, которые определяют когда пользовательские функции оцениваются, т. е. обычно только один раз на строку, или ваши результаты могут не соответствовать вашим ожиданиям).
Спектакль
Как указывает EBarr, с любым из вышеперечисленных могут быть проблемы с производительностью. Для более чем нескольких строк вы почти гарантированы, что вывод буферизуется в базу данных tempdb до того, как запрошенное количество строк будет прочитано в правильном порядке, что означает, что даже если вы ищете топ-10, вы можете найти полный индекс сканирование (или, что еще хуже, сканирование таблицы) происходит вместе с огромным блоком записи в базу данных tempdb. Поэтому может быть жизненно важно, как и в большинстве случаев, сравнить с реалистичными данными, прежде чем использовать их в производстве.