У меня есть таблица SQL Server с около 50 000 строк. Я хочу выбрать около 5000 из этих строк в случайном порядке. Я придумал сложный способ: создать временную таблицу со столбцом «случайное число», скопировать в нее свою таблицу, перебрать временную таблицу и обновить каждую строку с помощью RAND()
, а затем выбрать из этой таблицы столбец случайного числа < 0,1. Я ищу более простой способ сделать это, в одном утверждении, если это возможно.
В этой статье предлагается использовать NEWID()
функцию. Это выглядит многообещающе, но я не вижу, как я могу надежно выбрать определенный процент строк.
Кто-нибудь когда-нибудь делал это раньше? Любые идеи?
sql
sql-server
random
Джон М Гант
источник
источник
Ответы:
В ответ на комментарий «чистого мусора» относительно больших таблиц: вы можете сделать это так, чтобы улучшить производительность.
Стоимость этого будет ключевым сканированием значений плюс стоимость соединения, что для большой таблицы с небольшим процентным выбором должно быть разумным.
источник
[yourPk]
? РЕДАКТИРОВАТЬ: НВМ, понял это ... Первичный ключ. Durrrnewid()
стоимость ввода-вывода Sort Estimate будет очень высокой и повлияет на производительность.В зависимости от ваших потребностей,
TABLESAMPLE
вы получите почти такую же случайность и лучшую производительность. это доступно на сервере MS SQL 2005 и позже.TABLESAMPLE
будет возвращать данные со случайных страниц вместо случайных строк и, следовательно, даже не получит данные, которые они не будут возвращать.На очень большом столе я тестировал
заняло более 20 минут.
заняло 2 минуты.
Производительность также улучшится на небольших выборках,
TABLESAMPLE
тогда как не будет сnewid()
.Пожалуйста, имейте в виду, что это не так случайно, как
newid()
метод, но даст вам достойную выборку.Смотрите страницу MSDN .
источник
newid () / order by будет работать, но будет очень дорого для больших наборов результатов, потому что он должен генерировать id для каждой строки, а затем сортировать их.
TABLESAMPLE () хорош с точки зрения производительности, но вы получите совокупность результатов (будут возвращены все строки на странице).
Для лучшего выполнения истинной случайной выборки лучший способ состоит в том, чтобы отфильтровать строки случайным образом. Я нашел следующий пример кода в электронной документации по SQL Server. Ограничение наборов результатов с помощью TABLESAMPLE :
Когда я запускаю таблицу с 1 000 000 строк, вот мои результаты:
Если вы можете избежать использования TABLESAMPLE, это даст вам наилучшую производительность. В противном случае используйте метод newid () / filter. newid () / order by должен быть последним средством, если у вас большой набор результатов.
источник
NewID()
она оценивается только один раз, а не в каждой строке, что мне не нравится ...Выбор строк случайным образом из большой таблицы на MSDN имеет простое, хорошо сформулированное решение, которое решает проблемы производительности большого масштаба.
источник
RAND()
не возвращает одно и то же значение для каждой строки (что противоречитBINARY_CHECKSUM()
логике). Это потому, что он вызывается внутри другой функции, а не является частью предложения SELECT?rand()
или комбинацией вышеперечисленного - но я отказался от этого решения по этой причине. Кроме того, количество результатов варьировалось от 1 до 5, поэтому это может быть также неприемлемо в некоторых сценариях.RAND()
возвращает одно и то же значение для каждой строки (вот почему это решение быстрое). Однако строки с двоичными контрольными суммами, которые находятся очень близко друг к другу, подвергаются высокому риску получения аналогичных результатов контрольной суммы, вызывая комкование, когдаRAND()
оно мало. Например,(ABS(CAST((BINARY_CHECKSUM(111,null,null) * 0.1) as int))) % 100
==SELECT (ABS(CAST((BINARY_CHECKSUM(113,null,null) * 0.1) as int))) % 100
. Если ваши данные страдают от этой проблемы, умножьтеBINARY_CHECKSUM
на 9923.Эта ссылка имеет интересное сравнение между Orderby (NEWID ()) и другими методами для таблиц с 1, 7 и 13 миллионами строк.
Часто, когда в дискуссионных группах задаются вопросы о том, как выбрать случайные строки, предлагается запрос NEWID; это просто и работает очень хорошо для небольших столов.
Однако запрос NEWID имеет большой недостаток, когда вы используете его для больших таблиц. Предложение ORDER BY вызывает копирование всех строк в таблице в базу данных tempdb, где они сортируются. Это вызывает две проблемы:
Вам нужен способ случайного выбора строк, который не будет использовать базу данных tempdb и не станет намного медленнее по мере увеличения таблицы. Вот новая идея о том, как это сделать:
Основная идея этого запроса заключается в том, что мы хотим сгенерировать случайное число от 0 до 99 для каждой строки в таблице, а затем выбрать все те строки, случайное число которых меньше значения указанного процента. В этом примере мы хотим, чтобы приблизительно 10 процентов строк были выбраны случайным образом; поэтому мы выбираем все строки, случайное число которых меньше 10.
Пожалуйста, прочитайте полную статью в MSDN .
источник
Если вам (в отличие от OP) требуется определенное количество записей (что затрудняет подход к CHECKSUM) и вы хотите получить более случайную выборку, чем сама TABLESAMPLE, а также хотите получить более высокую скорость, чем CHECKSUM, вы можете обойтись путем объединения Методы TABLESAMPLE и NEWID (), например:
В моем случае это самый простой компромисс между случайностью (это не совсем, я знаю) и скоростью. Изменяйте процент TABLESAMPLE (или строки) в зависимости от ситуации - чем выше процент, тем более случайная выборка, но ожидайте линейного падения скорости. (Обратите внимание, что TABLESAMPLE не примет переменную)
источник
Просто упорядочите таблицу по случайному числу и получите первые 5000 строк, используя
TOP
.ОБНОВИТЬ
Только что попробовал, и
newid()
вызова достаточно - нет необходимости во всех забрасываниях и всей математике.источник
Это комбинация первоначальной исходной идеи и контрольной суммы, которая, как мне кажется, дает правильные случайные результаты без затрат NEWID ():
источник
В MySQL вы можете сделать это:
источник
Я еще не видел эту вариацию в ответах. У меня было дополнительное ограничение, когда мне нужно, учитывая начальное начальное число, каждый раз выбирать один и тот же набор строк.
Для MS SQL:
Минимальный пример:
Нормализованное время выполнения: 1,00
Пример NewId ():
Нормализованное время выполнения: 1,02
NewId()
незначительно медленнее, чемrand(checksum(*))
, поэтому вы можете не использовать его для больших наборов записей.Выбор с начальным семенем:
Если вам нужно выбрать один и тот же набор с учетом начального числа, это, похоже, работает.
источник
Попробуй это:
источник
Похоже, newid () не может использоваться в предложении where, поэтому для этого решения требуется внутренний запрос:
источник
Я использовал его в подзапросе, и он вернул мне те же строки в подзапросе
Затем я решил с включением родительской переменной таблицы, где
Обратите внимание, где условия
источник
Используемый язык обработки на стороне сервера (например, PHP, .net и т. Д.) Не указан, но если это PHP, возьмите требуемое число (или все записи) и вместо рандомизации в запросе используйте PHP-функцию shuffle. Я не знаю, если .net имеет эквивалентную функцию, но если она есть, то используйте ее, если вы используете .net
ORDER BY RAND () может привести к значительному снижению производительности в зависимости от того, сколько записей задействовано.
источник
Это работает для меня:
источник
select top 10 percent from table_name order by rand()
, но это также не работает, потому что rand () возвращает одинаковое значение во всех строках.