Десять лет назад один парень сказал, что использовать ORDER BY RAND()это неправильно ...
Трейдер
ORDER BY NEWID (), кажется, заметно медленнее на SQL Server. Мой запрос выглядит следующим образом: выберите топ 1000 C.CustomerId, CL.LoginName из внутреннего соединения Customer C LinkedAccount LA на C.CustomerId = LA.CustomerId внутреннего соединения CustomerLogin CL в C.CustomerId = CL.CustomerId с помощью C.CustomerId, CL. Имя_пользователя, имеющее счет (*)> 1 порядка по NEWID () Удаление строки «порядок по NEWID ()» возвращает результаты намного быстрее.
Бен Пауэр
3
Для SQLite используйте функцию RANDOM ().
Шлем
10
Эти решения не масштабируются. Они O(n)с nколичеством записей в таблице. Представьте, что у вас есть 1 миллион записей, вы действительно хотите сгенерировать 1 миллион случайных чисел или уникальных идентификаторов? Я бы лучше использовал COUNT()и включил это в новое LIMITвыражение с одним случайным числом.
Кристиан Худжер
174
Решения, такие как Джеремис:
SELECT*FROMtableORDERBY RAND() LIMIT 1
работают, но им требуется последовательное сканирование всей таблицы (поскольку необходимо вычислить случайное значение, связанное с каждой строкой, чтобы можно было определить наименьшее значение), что может быть довольно медленным даже для таблиц среднего размера. Я бы порекомендовал использовать какой-то индексированный числовой столбец (многие таблицы имеют их в качестве своих первичных ключей), а затем написать что-то вроде:
SELECT*FROMtableWHERE num_value >= RAND()*(SELECT MAX (num_value )FROMtable)ORDERBY num_value LIMIT 1
Это работает в логарифмическом времени, независимо от размера таблицы, если num_valueона проиндексирована. Одно предостережение: предполагается, что num_valueоно равномерно распределено по диапазону 0..MAX(num_value). Если ваш набор данных сильно отклоняется от этого предположения, вы получите искаженные результаты (некоторые строки будут появляться чаще, чем другие).
Второе предложение не случайно. Вы не можете предсказать строку, которая будет выбрана, но если бы вам пришлось делать ставку, вы бы сделали ставку на второй ряд. И вы никогда не сделаете ставку на последнюю строку, это будет менее вероятным выбором независимо от распределения вашего num_value и размера таблицы.
Этьен Расин
1
Я знаю, что обычно функции RAND () не очень высокого качества, но, кроме этого, не могли бы вы пояснить, почему выбор не будет случайным?
Серая пантера
13
Первый - НЕПРАВИЛЬНО в SQL Server. Функция RAND () вызывается только один раз на запрос, а не один раз на строку. Поэтому он всегда выбирает первый ряд (попробуйте).
Джефф Уокер Код Рейнджер
3
Второй также предполагает, что все строки учтены: возможно, он выберет строку, которая была удалена.
Сэм Рюби
3
@ Sam.Rueby На самом деле, num_value> = RAND () ... предел 1 гарантирует, что пустые строки будут пропущены, пока не будет найдена существующая строка.
хорд
62
Я не знаю, насколько это эффективно, но я использовал это раньше:
SELECTTOP1*FROM MyTable ORDERBY newid()
Поскольку GUID довольно случайный, порядок означает, что вы получите случайную строку.
Я использую сервер MS SQL, SELECT TOP 1 * FROM some_table_name ORDER BY NEWID () отлично работает для меня, спасибо за советы, ребята!
Это точно так же, какORDER BY RAND() LIMIT 1
Кен Блум
6
Это также очень специфично для базы данных, так как использует TOP 1и newid().
Серый
12
Это плохая идея. Этот метод не будет использовать индекс, если каждый столбец не индексируется по отдельности. Таблица с 100 миллионами записей может занять очень много времени, чтобы получить одну запись.
Переключатель
1
@ Переключатель, а какое решение вы бы предложили?
Акмаль Салихов,
31
ORDERBY NEWID()
принимает 7.4 milliseconds
WHERE num_value >= RAND()*(SELECT MAX(num_value)FROMtable)
Второй вариант не выберет последний ряд. Я не знаю почему - просто указывает на это.
Волдеморт
7
@Voldemort: rand()возвращает число с плавающей точкой, nгде 0 < n < 1. Предполагая, num_valueчто это целое число, возвращаемое значение rand() * max(num_value)будет также приведено к целому числу, таким образом обрезая что-либо после десятичной точки. Следовательно, rand() * max(num_value)будет всегда меньше max(num_value), поэтому никогда не будет выбрана последняя строка.
Ян Кемп
Я не буду эффективен, если мои данные будут часто удаляться - если я найду пробел, мне придется повторно выполнить весь запрос.
Лоик Коенен
1
@IanKemp Глупый вопрос, так почему бы не использовать SELECT MAX (num_value) + 1 ?? Поскольку rand (или RANDOM в большинстве случаев) возвращает [0,1), вы получите полный диапазон значений. Кроме того, да, вы правы, нужно исправить запрос.
tekHedd
13
Вы не сказали, какой сервер вы используете. В более старых версиях SQL Server вы можете использовать это:
selecttop1*from mytable orderby newid()
В SQL Server 2005 и более поздних версиях вы можете использовать TABLESAMPLEслучайную выборку, которая будет повторяться:
SELECT FirstName, LastName
FROM Contact
TABLESAMPLE (1ROWS);
newid () / order by будет работать, но будет очень дорого для больших наборов результатов, потому что он должен генерировать id для каждой строки, а затем сортировать их.
TABLESAMPLE () хорош с точки зрения производительности, но вы получите совокупность результатов (будут возвращены все строки на странице).
Для лучшего выполнения истинной случайной выборки лучшим способом является случайная фильтрация строк. Я нашел следующий пример кода в электронной документации по SQL Server. Ограничение наборов результатов с помощью TABLESAMPLE :
Если вам действительно нужна случайная выборка отдельных строк, измените запрос, чтобы отфильтровать строки случайным образом, вместо использования TABLESAMPLE. Например, следующий запрос использует функцию NEWID для возврата приблизительно одного процента строк таблицы Sales.SalesOrderDetail:
Столбец SalesOrderID включен в выражение CHECKSUM, поэтому NEWID () оценивается один раз для каждой строки, чтобы получить выборку для каждой строки. Выражение CAST (CHECKSUM (NEWID (), SalesOrderID) & 0x7fffffff AS float / CAST (0x7fffffff AS int) оценивается как случайное значение с плавающей точкой между 0 и 1).
Когда я запускаю таблицу с 1 000 000 строк, вот мои результаты:
SETSTATISTICS TIME ONSETSTATISTICS IO ON/* newid()
rows returned: 10000
logical reads: 3359
CPU time: 3312 ms
elapsed time = 3359 ms
*/SELECTTOP1PERCENT Number
FROM Numbers
ORDERBY newid()/* TABLESAMPLE
rows returned: 9269 (varies)
logical reads: 32
CPU time: 0 ms
elapsed time: 5 ms
*/SELECT Number
FROM Numbers
TABLESAMPLE (1PERCENT)/* Filter
rows returned: 9994 (varies)
logical reads: 3359
CPU time: 641 ms
elapsed time: 627 ms
*/SELECT Number
FROM Numbers
WHERE0.01>= CAST(CHECKSUM(NEWID(), Number)&0x7fffffffAS float)/ CAST (0x7fffffffAS int)SETSTATISTICS IO OFFSETSTATISTICS TIME OFF
Если вам удастся избежать использования TABLESAMPLE, это даст вам наилучшую производительность. В противном случае используйте метод newid () / filter. newid () / order by должен быть последним средством, если у вас большой набор результатов.
Если возможно, используйте сохраненные операторы, чтобы избежать неэффективности обоих индексов в RND () и создания поля номера записи.
ПОДГОТОВИТЬ RandomRecord FROM "SELECT * FROM table LIMIT?, 1";
SET @ n = FLOOR (RAND () * (ВЫБЕРИТЕ СЧЕТЧИК (*) ИЗ таблицы));
EXECUTE RandomRecord USING @n;
Это решение также заботится о возвращении случайных строк, когда индексированное числовое значение, используемое в приведенном выше предложении where, распределено неравномерно; так что даже если это занимает почти то же самое (постоянное) время, что и при использовании где id_value> = RAND () * MAX (id_value), это лучше.
Гидо
Насколько я могу сказать, это не работает в постоянное время, оно работает в линейное время. В худшем случае @n равно количеству строк в таблице, а «SELECT * FROM table LIMIT?, 1» оценивает @n - 1 строк до тех пор, пока не доберется до последней.
Андрес Риофрио
3
Лучший способ - поместить случайное значение в новый столбец только для этой цели и использовать что-то вроде этого (псевдокод + SQL):
randomNo = random()
execSql("SELECT TOP 1 * FROM MyTable WHERE MyTable.Randomness > $randomNo")
Это решение, используемое кодом MediaWiki. Конечно, есть некоторое смещение против меньших значений, но они обнаружили, что было достаточно обернуть случайное значение в ноль, когда не выбираются строки.
Для решения newid () может потребоваться полное сканирование таблицы, чтобы каждой строке можно было присвоить новый guid, который будет гораздо менее производительным.
Решение rand () может вообще не работать (т.е. с MSSQL), потому что функция будет оценена только один раз, и каждой строке будет присвоен один и тот же «случайный» номер.
Обтекание, когда вы получаете 0 результатов, обеспечивает доказуемо случайную выборку (а не только «достаточно хорошую»). Это решение практически масштабируется до многострочных запросов (например, «перестановка вечеринок»). Проблема в том, что результаты, как правило, выбираются в одних и тех же группах неоднократно. Чтобы обойти это, вам нужно будет перераспределить случайные числа, которые вы только что использовали. Вы можете обмануть, отслеживая randomNo и устанавливая его в max (randomness) из результатов, но затем p (строка i в запросе 1 и строка i в запросе 2) == 0, что не справедливо. Позвольте мне немного посчитать, и я вернусь к вам с действительно честной схемой.
Alsuren
3
Для SQL Server 2005 и 2008, если мы хотим случайную выборку отдельных строк (из Books Online ):
SELECT ID FROMTABLEWHERE ID >= My_Generated_Random ORDERBY ID LIMIT 1
Обратите внимание, что он проверит для всех строк, идентификаторы которых равны или выше, чем выбранное значение. Также можно найти строку внизу таблицы и получить равный или меньший идентификатор, чем My_Generated_Random, а затем изменить запрос следующим образом:
SELECT ID FROMTABLEWHERE ID <= My_Generated_Random ORDERBY ID DESC LIMIT 1
Что произойдет, если сгенерированный случайный идентификатор больше не существует в таблице? Удаленные или пассивные строки, которые вы не хотите показывать пользователю, могут вызвать проблемы.
Ebleme
Ничего. Вы получите БЛИЖАЙШИЙ, не точный, идентификационный номер. Если вы считаете, что id = 1 будет удалено, поменяйте 1 на минимум.
Форсберг
2
Как указано в комментарии @ BillKarwin к ответу @ cnu ...
При объединении с LIMIT я обнаружил, что он работает намного лучше (по крайней мере, с PostgreSQL 9.1) для JOIN со случайным порядком, а не для непосредственного упорядочения фактических строк: например,
SELECT*FROM tbl_post AS t
JOIN...JOIN(SELECT id, CAST(-2147483648* RANDOM()AS integer)AS rand
FROM tbl_post
WHERE create_time >=1349928000) r ON r.id = t.id
WHERE create_time >=1349928000AND...ORDERBY r.rand
LIMIT 100
Просто убедитесь, что 'r' генерирует значение 'rand' для каждого возможного значения ключа в сложном запросе, который связан с ним, но все же ограничивает количество строк 'r', где это возможно.
CAST as Integer особенно полезен для PostgreSQL 9.2, который имеет специальную оптимизацию сортировки для целочисленных и плавающих типов одинарной точности.
Большинство решений здесь направлены на то, чтобы избежать сортировки, но им все равно необходимо последовательно сканировать таблицу.
Существует также способ избежать последовательного сканирования, переключившись на индексное сканирование. Если вы знаете значение индекса вашей случайной строки, вы можете получить результат почти мгновенно. Проблема в том, как угадать значение индекса.
Следующее решение работает на PostgreSQL 8.4:
explain analyze select*from cms_refs where rec_id in(select(random()*(select last_value from cms_refs_rec_id_seq))::bigint
from generate_series(1,10))
limit 1;
В приведенном выше решении вы угадаете 10 различных случайных значений индекса из диапазона 0 .. [последнее значение id].
Число 10 произвольно - вы можете использовать 100 или 1000, так как оно (как ни удивительно) не сильно влияет на время отклика.
Есть также одна проблема - если у вас есть редкие идентификаторы, вы можете пропустить . Решение состоит в том, чтобы иметь план резервного копирования :) В этом случае чистый старый порядок по запросу random (). Когда объединенный идентификатор выглядит так:
explain analyze select*from cms_refs where rec_id in(select(random()*(select last_value from cms_refs_rec_id_seq))::bigint
from generate_series(1,10))unionall(select*from cms_refs orderby random() limit 1)
limit 1;
Не союз ВСЕ оговорка. В этом случае, если первая часть возвращает какие-либо данные, вторая НИКОГДА не выполняется!
В конце, но попал сюда через гугл, поэтому ради потомков добавлю альтернативное решение.
Другой подход состоит в том, чтобы использовать ТОП дважды, с чередующимися ордерами. Я не знаю, является ли это «чистым SQL», потому что он использует переменную в TOP, но он работает в SQL Server 2008. Вот пример, который я использую для таблицы словарных слов, если я хочу случайное слово.
SELECTTOP1
word
FROM(SELECTTOP(@idx)
word
FROM
dbo.DictionaryAbridged WITH(NOLOCK)ORDERBY
word DESC)AS D
ORDERBY
word ASC
Конечно, @idx - это случайное целое число в диапазоне от 1 до COUNT (*) на целевой таблице включительно. Если ваш столбец проиндексирован, вы тоже извлечете из него пользу. Другое преимущество заключается в том, что вы можете использовать его в функции, поскольку NEWID () не разрешен.
Наконец, вышеупомянутый запрос выполняется примерно за 1/10 времени выполнения запроса NEWID () для той же таблицы. YYMV.
После проверки многих ответов, я считаю, что это лучший. Кажется, это быстро и выбирает хорошее случайное число каждый раз. Это похоже на второе предложение @GreyPanther выше, но этот ответ выбирает больше случайных чисел.
Джефф Бейкер
1
Я еще не видел эту вариацию в ответах. У меня было дополнительное ограничение, когда мне нужно, учитывая начальное начальное число, каждый раз выбирать один и тот же набор строк.
NewId()незначительно медленнее, чем rand(checksum(*)), поэтому вы можете не использовать его для больших наборов записей.
Выбор с начальным семенем:
declare@seed int
set@seed = Year(getdate())* month(getdate())/* any other initial seed here */selecttop10percent*from table_name
orderby rand(checksum(*)% seed)/* any other math function here */
Если вам нужно выбрать один и тот же набор с учетом начального числа, это, похоже, работает.
В SQL Server вы можете комбинировать TABLESAMPLE с NEWID (), чтобы получить довольно хорошую случайность и при этом иметь скорость. Это особенно полезно, если вы действительно хотите только 1 или небольшое количество строк.
В SQL Server 2012+ вы можете использовать запрос OFFSET FETCH, чтобы сделать это для одной случайной строки
select*from MyTable ORDERBY id OFFSET n ROWFETCH NEXT 1ROWS ONLY
где id - это столбец идентификаторов, а n - нужная строка - рассчитывается как случайное число от 0 до count () - 1 таблицы (смещение 0 - первая строка после всех)
Это работает с дырами в табличных данных, если у вас есть индекс для работы с предложением ORDER BY. Это также очень хорошо для случайности - так как вы сами решаете, что нужно пройти, но срывов в других методах нет. Кроме того, производительность довольно хорошая, на меньшем наборе данных она хорошо держится, хотя я не пробовал серьезных тестов производительности на нескольких миллионах строк.
Десять лет назад (2005) какой-то парень сказал, что использовать ORDER BY RAND()это неправильно ...
trejder
0
Я должен согласиться с CD-MaN: использование «ORDER BY RAND ()» будет хорошо работать для небольших столов или когда вы делаете SELECT только несколько раз.
Я также использую технику «num_value> = RAND () * ...», и если я действительно хочу получить случайные результаты, у меня есть специальный «случайный» столбец в таблице, который я обновляю раз в день или около того. Этот единственный прогон UPDATE займет некоторое время (особенно потому, что у вас должен быть индекс для этого столбца), но это намного быстрее, чем создание случайных чисел для каждой строки каждый раз, когда выполняется выбор.
Будьте осторожны, поскольку TableSample на самом деле не возвращает случайную выборку строк. Он направляет ваш запрос на случайную выборку страниц размером 8 КБ, составляющих вашу строку. Затем ваш запрос выполняется по данным, содержащимся на этих страницах. Из-за того, как данные могут быть сгруппированы на этих страницах (порядок вставки и т. Д.), Это может привести к тому, что данные на самом деле не являются случайной выборкой.
Кажется, что многие из перечисленных идей все еще используют порядок
Однако, если вы используете временную таблицу, вы можете назначить случайный индекс (как предлагали многие решения), а затем получить первый, который больше произвольного числа от 0 до 1.
Например (для DB2):
WITH TEMP AS(SELECT COMLUMN, RAND()AS IDX FROMTABLE)SELECTCOLUMNFROMTABLEWHERE IDX >.5FETCH FIRST 1ROW ONLY
После рассмотрения этого решения я обнаружил фундаментальный недостаток в моей логике. Это будет последовательно возвращать одни и те же небольшие значения настройки в начале таблицы, потому что я предполагаю, что если бы было равномерное распределение между 0 и 1, есть 50% -ная вероятность того, что первая строка будет соответствовать этим критериям.
Для Oracle есть лучшее решение вместо использования dbms_random.value, в то время как для упорядочивания строк по dbms_random.value требуется полное сканирование, а для больших таблиц это довольно медленно.
Для SQL Server 2005 и выше, расширение ответа @ GreyPanther для случаев, когда num_valueзначения не являются непрерывными. Это работает также для случаев, когда у нас нет равномерно распределенных наборов данных, и когда num_valueэто не число, а уникальный идентификатор.
WITH CTE_Table (SelRow, num_value)AS(SELECT ROW_NUMBER()OVER(ORDERBY ID)AS SelRow, num_value FROMtable)SELECT*FROMtableWhere num_value =(SELECTTOP1 num_value FROM CTE_Table WHERE SelRow >= RAND()*(SELECT MAX(SelRow)FROM CTE_Table))
Ответы:
Смотрите этот пост: SQL для выбора случайной строки из таблицы базы данных . Он проходит методы для этого в MySQL, PostgreSQL, Microsoft SQL Server, IBM DB2 и Oracle (по этой ссылке скопировано следующее):
Выберите случайную строку с MySQL:
Выберите случайную строку с PostgreSQL:
Выберите случайную строку с Microsoft SQL Server:
Выберите случайную строку с IBM DB2
Выберите случайную запись с Oracle:
источник
order by rand()
или эквивалентов во всех dbs: |. также упоминается здесь .ORDER BY RAND()
это неправильно ...O(n)
сn
количеством записей в таблице. Представьте, что у вас есть 1 миллион записей, вы действительно хотите сгенерировать 1 миллион случайных чисел или уникальных идентификаторов? Я бы лучше использовалCOUNT()
и включил это в новоеLIMIT
выражение с одним случайным числом.Решения, такие как Джеремис:
работают, но им требуется последовательное сканирование всей таблицы (поскольку необходимо вычислить случайное значение, связанное с каждой строкой, чтобы можно было определить наименьшее значение), что может быть довольно медленным даже для таблиц среднего размера. Я бы порекомендовал использовать какой-то индексированный числовой столбец (многие таблицы имеют их в качестве своих первичных ключей), а затем написать что-то вроде:
Это работает в логарифмическом времени, независимо от размера таблицы, если
num_value
она проиндексирована. Одно предостережение: предполагается, чтоnum_value
оно равномерно распределено по диапазону0..MAX(num_value)
. Если ваш набор данных сильно отклоняется от этого предположения, вы получите искаженные результаты (некоторые строки будут появляться чаще, чем другие).источник
Я не знаю, насколько это эффективно, но я использовал это раньше:
Поскольку GUID довольно случайный, порядок означает, что вы получите случайную строку.
источник
ORDER BY RAND() LIMIT 1
TOP 1
иnewid()
.принимает
7.4 milliseconds
берет
0.0065 milliseconds
!Я определенно пойду с последним методом.
источник
rand()
возвращает число с плавающей точкой,n
где0 < n < 1
. Предполагая,num_value
что это целое число, возвращаемое значениеrand() * max(num_value)
будет также приведено к целому числу, таким образом обрезая что-либо после десятичной точки. Следовательно,rand() * max(num_value)
будет всегда меньшеmax(num_value)
, поэтому никогда не будет выбрана последняя строка.Вы не сказали, какой сервер вы используете. В более старых версиях SQL Server вы можете использовать это:
В SQL Server 2005 и более поздних версиях вы можете использовать
TABLESAMPLE
случайную выборку, которая будет повторяться:источник
Для SQL Server
newid () / order by будет работать, но будет очень дорого для больших наборов результатов, потому что он должен генерировать id для каждой строки, а затем сортировать их.
TABLESAMPLE () хорош с точки зрения производительности, но вы получите совокупность результатов (будут возвращены все строки на странице).
Для лучшего выполнения истинной случайной выборки лучшим способом является случайная фильтрация строк. Я нашел следующий пример кода в электронной документации по SQL Server. Ограничение наборов результатов с помощью TABLESAMPLE :
Когда я запускаю таблицу с 1 000 000 строк, вот мои результаты:
Если вам удастся избежать использования TABLESAMPLE, это даст вам наилучшую производительность. В противном случае используйте метод newid () / filter. newid () / order by должен быть последним средством, если у вас большой набор результатов.
источник
Если возможно, используйте сохраненные операторы, чтобы избежать неэффективности обоих индексов в RND () и создания поля номера записи.
источник
Лучший способ - поместить случайное значение в новый столбец только для этой цели и использовать что-то вроде этого (псевдокод + SQL):
Это решение, используемое кодом MediaWiki. Конечно, есть некоторое смещение против меньших значений, но они обнаружили, что было достаточно обернуть случайное значение в ноль, когда не выбираются строки.
Для решения newid () может потребоваться полное сканирование таблицы, чтобы каждой строке можно было присвоить новый guid, который будет гораздо менее производительным.
Решение rand () может вообще не работать (т.е. с MSSQL), потому что функция будет оценена только один раз, и каждой строке будет присвоен один и тот же «случайный» номер.
источник
Для SQL Server 2005 и 2008, если мы хотим случайную выборку отдельных строк (из Books Online ):
источник
Вместо того, чтобы использовать RAND (), так как это не рекомендуется , вы можете просто получить max ID (= Max):
получить случайное значение между 1.Max (= My_Generated_Random)
и затем запустите этот SQL:
Обратите внимание, что он проверит для всех строк, идентификаторы которых равны или выше, чем выбранное значение. Также можно найти строку внизу таблицы и получить равный или меньший идентификатор, чем My_Generated_Random, а затем изменить запрос следующим образом:
источник
Как указано в комментарии @ BillKarwin к ответу @ cnu ...
При объединении с LIMIT я обнаружил, что он работает намного лучше (по крайней мере, с PostgreSQL 9.1) для JOIN со случайным порядком, а не для непосредственного упорядочения фактических строк: например,
Просто убедитесь, что 'r' генерирует значение 'rand' для каждого возможного значения ключа в сложном запросе, который связан с ним, но все же ограничивает количество строк 'r', где это возможно.
CAST as Integer особенно полезен для PostgreSQL 9.2, который имеет специальную оптимизацию сортировки для целочисленных и плавающих типов одинарной точности.
источник
Большинство решений здесь направлены на то, чтобы избежать сортировки, но им все равно необходимо последовательно сканировать таблицу.
Существует также способ избежать последовательного сканирования, переключившись на индексное сканирование. Если вы знаете значение индекса вашей случайной строки, вы можете получить результат почти мгновенно. Проблема в том, как угадать значение индекса.
Следующее решение работает на PostgreSQL 8.4:
В приведенном выше решении вы угадаете 10 различных случайных значений индекса из диапазона 0 .. [последнее значение id].
Число 10 произвольно - вы можете использовать 100 или 1000, так как оно (как ни удивительно) не сильно влияет на время отклика.
Есть также одна проблема - если у вас есть редкие идентификаторы, вы можете пропустить . Решение состоит в том, чтобы иметь план резервного копирования :) В этом случае чистый старый порядок по запросу random (). Когда объединенный идентификатор выглядит так:
Не союз ВСЕ оговорка. В этом случае, если первая часть возвращает какие-либо данные, вторая НИКОГДА не выполняется!
источник
В конце, но попал сюда через гугл, поэтому ради потомков добавлю альтернативное решение.
Другой подход состоит в том, чтобы использовать ТОП дважды, с чередующимися ордерами. Я не знаю, является ли это «чистым SQL», потому что он использует переменную в TOP, но он работает в SQL Server 2008. Вот пример, который я использую для таблицы словарных слов, если я хочу случайное слово.
Конечно, @idx - это случайное целое число в диапазоне от 1 до COUNT (*) на целевой таблице включительно. Если ваш столбец проиндексирован, вы тоже извлечете из него пользу. Другое преимущество заключается в том, что вы можете использовать его в функции, поскольку NEWID () не разрешен.
Наконец, вышеупомянутый запрос выполняется примерно за 1/10 времени выполнения запроса NEWID () для той же таблицы. YYMV.
источник
Вы также можете попробовать использовать
new id()
функцию.Просто напишите свой запрос и используйте порядок по
new id()
функциям. Это довольно случайно.источник
Для MySQL получить случайную запись
Более подробно http://jan.kneschke.de/projects/mysql/order-by-rand/
источник
Я еще не видел эту вариацию в ответах. У меня было дополнительное ограничение, когда мне нужно, учитывая начальное начальное число, каждый раз выбирать один и тот же набор строк.
Для MS SQL:
Минимальный пример:
Нормализованное время выполнения: 1,00
Пример NewId ():
Нормализованное время выполнения: 1,02
NewId()
незначительно медленнее, чемrand(checksum(*))
, поэтому вы можете не использовать его для больших наборов записей.Выбор с начальным семенем:
Если вам нужно выбрать один и тот же набор с учетом начального числа, это, похоже, работает.
источник
В MSSQL (протестировано на 11.0.5569) используется
значительно быстрее, чем
источник
В SQL Server вы можете комбинировать TABLESAMPLE с NEWID (), чтобы получить довольно хорошую случайность и при этом иметь скорость. Это особенно полезно, если вы действительно хотите только 1 или небольшое количество строк.
источник
В SQL Server 2012+ вы можете использовать запрос OFFSET FETCH, чтобы сделать это для одной случайной строки
где id - это столбец идентификаторов, а n - нужная строка - рассчитывается как случайное число от 0 до count () - 1 таблицы (смещение 0 - первая строка после всех)
Это работает с дырами в табличных данных, если у вас есть индекс для работы с предложением ORDER BY. Это также очень хорошо для случайности - так как вы сами решаете, что нужно пройти, но срывов в других методах нет. Кроме того, производительность довольно хорошая, на меньшем наборе данных она хорошо держится, хотя я не пробовал серьезных тестов производительности на нескольких миллионах строк.
источник
источник
ORDER BY RAND()
это неправильно ...Я должен согласиться с CD-MaN: использование «ORDER BY RAND ()» будет хорошо работать для небольших столов или когда вы делаете SELECT только несколько раз.
Я также использую технику «num_value> = RAND () * ...», и если я действительно хочу получить случайные результаты, у меня есть специальный «случайный» столбец в таблице, который я обновляю раз в день или около того. Этот единственный прогон UPDATE займет некоторое время (особенно потому, что у вас должен быть индекс для этого столбца), но это намного быстрее, чем создание случайных чисел для каждой строки каждый раз, когда выполняется выбор.
источник
Будьте осторожны, поскольку TableSample на самом деле не возвращает случайную выборку строк. Он направляет ваш запрос на случайную выборку страниц размером 8 КБ, составляющих вашу строку. Затем ваш запрос выполняется по данным, содержащимся на этих страницах. Из-за того, как данные могут быть сгруппированы на этих страницах (порядок вставки и т. Д.), Это может привести к тому, что данные на самом деле не являются случайной выборкой.
См .: http://www.mssqltips.com/tip.asp?tip=1308.
Эта страница MSDN для TableSample включает в себя пример того, как генерировать действительно случайную выборку данных.
http://msdn.microsoft.com/en-us/library/ms189108.aspx
источник
Кажется, что многие из перечисленных идей все еще используют порядок
Однако, если вы используете временную таблицу, вы можете назначить случайный индекс (как предлагали многие решения), а затем получить первый, который больше произвольного числа от 0 до 1.
Например (для DB2):
источник
Простой и эффективный способ от http://akinas.com/pages/en/blog/mysql_random_row/
источник
Для Oracle есть лучшее решение вместо использования dbms_random.value, в то время как для упорядочивания строк по dbms_random.value требуется полное сканирование, а для больших таблиц это довольно медленно.
Используйте это вместо:
источник
Для Firebird:
источник
Для SQL Server 2005 и выше, расширение ответа @ GreyPanther для случаев, когда
num_value
значения не являются непрерывными. Это работает также для случаев, когда у нас нет равномерно распределенных наборов данных, и когдаnum_value
это не число, а уникальный идентификатор.источник
Случайная функция из sql может помочь. Также, если вы хотите ограничиться только одной строкой, просто добавьте это в конце.
источник