Выберите n случайных строк из таблицы SQL Server
у меня есть таблица SQL Server с примерно 50 000 строк в нем. Я хочу выбрать около 5000 из этих строк наугад. Я придумал сложный способ, создав временную таблицу со столбцом "случайное число", скопировав в нее мою таблицу, пройдя через временную таблицу и обновив каждую строку с помощью RAND(), а затем выбрать из этой таблицы, где столбец случайных чисел
этот статья предлагают использовать
15 ответов:
select top 10 percent * from [yourtable] order by newid()в ответ на комментарий "чистый мусор" относительно больших таблиц: вы можете сделать это так, чтобы улучшить производительность.
select * from [yourtable] where [yourPk] in (select top 10 percent [yourPk] from [yourtable] order by newid())стоимость этого будет ключевым сканированием значений плюс стоимость соединения, которая на большой таблице с небольшим процентным выбором должна быть разумной.
в зависимости от ваших потребностей,
TABLESAMPLEбудет Вам почти как случайный и лучшую производительность. это доступно в MS SQL server 2005 и более поздних версиях.
TABLESAMPLEбудет возвращать данные из случайных страниц вместо случайных строк, и поэтому deos даже не извлекает данные, которые он не вернет.на очень большом столе я тестировал
select top 1 percent * from [tablename] order by newid()заняло более 20 минут.
select * from [tablename] tablesample(1 percent)заняло 2 минуты.
производительность также улучшится меньшие образцы в
TABLESAMPLEа не сnewid().пожалуйста, имейте в виду, что это не так случайно, как
newid()метод, но даст вам достойный отбор.посмотреть страница MSDN.
newid () / order by будет работать, но будет очень дорого для больших результирующих наборов, потому что он должен генерировать идентификатор для каждой строки, а затем сортировать их.
TABLESAMPLE () хорош с точки зрения производительности, но вы получите сгущение результатов (все строки на странице будут возвращены).
для лучшего выполнения истинной случайной выборки лучший способ - отфильтровать строки случайным образом. Я нашел следующий пример кода в статье электронной документации по SQL Server ограничение результирующих наборов с помощью предложения tablesample:
Если вы действительно хотите случайную выборку отдельные строки, измените запрос на отфильтровать строки случайным образом, а не используя TABLESAMPLE. Например, следующий запрос использует новый идентификатор функция возвращает примерно процент от числа строк Продажи.Таблица SalesOrderDetail:
SELECT * FROM Sales.SalesOrderDetail WHERE 0.01 >= CAST(CHECKSUM(NEWID(),SalesOrderID) & 0x7fffffff AS float) / CAST (0x7fffffff AS int)столбец SalesOrderID включен в выражение контрольной суммы так, что Функция newid() вычисляется один раз для каждой строки в достигните забора на основание в-строки. Выражение CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff как поплавок / CAST (0x7fffffff AS int) вычисляется следующим образом случайное значение с плавающей запятой между 0 и 1.
при запуске таблицы с 1 000 000 строк, вот мои результаты:
SET STATISTICS TIME ON SET STATISTICS IO ON /* newid() rows returned: 10000 logical reads: 3359 CPU time: 3312 ms elapsed time = 3359 ms */ SELECT TOP 1 PERCENT Number FROM Numbers ORDER BY newid() /* TABLESAMPLE rows returned: 9269 (varies) logical reads: 32 CPU time: 0 ms elapsed time: 5 ms */ SELECT Number FROM Numbers TABLESAMPLE (1 PERCENT) /* Filter rows returned: 9994 (varies) logical reads: 3359 CPU time: 641 ms elapsed time: 627 ms */ SELECT Number FROM Numbers WHERE 0.01 >= CAST(CHECKSUM(NEWID(), Number) & 0x7fffffff AS float) / CAST (0x7fffffff AS int) SET STATISTICS IO OFF SET STATISTICS TIME OFFЕсли вы можете уйти с помощью TABLESAMPLE, это даст вам лучшую производительность. В противном случае используйте метод newid()/filter. newid () / order by должно быть в крайнем случае, если у вас есть большой результирующий набор.
выбор строк случайным образом из большой таблицы на MSDN есть простое, хорошо сформулированное решение, которое решает проблемы крупномасштабной производительности.
SELECT * FROM Table1 WHERE (ABS(CAST( (BINARY_CHECKSUM(*) * RAND()) as int)) % 100) < 10
Если вам (в отличие от OP) нужно определенное количество записей (что затрудняет подход к контрольной сумме) и вы хотите получить более случайную выборку, чем TABLESAMPLE, а также хотите получить лучшую скорость, чем контрольная сумма, вы можете сделать это с помощью слияния методов TABLESAMPLE и NEWID (), например:
DECLARE @sampleCount int = 50 SET STATISTICS TIME ON SELECT TOP (@sampleCount) * FROM [yourtable] TABLESAMPLE(10 PERCENT) ORDER BY NEWID() SET STATISTICS TIME OFFв моем случае это самый простой компромисс между случайностью (это не совсем так, я знаю) и скоростью. Измените процентный показатель TABLESAMPLE (или строки) следующим образом соответствующий-чем выше процент, тем более случайна выборка, но ожидайте линейного снижения скорости. (Обратите внимание, что TABLESAMPLE не принимает переменную)
просто закажите таблицу по случайному числу и получите первые 5000 строк с помощью
TOP.SELECT TOP 5000 * FROM [Table] ORDER BY newid();обновление
просто попробовал и
newid()вызов достаточен - нет необходимости во всех бросках и всей математике.
эта ссылка имеет интересное сравнение между Orderby (NEWID ()) и другими методами для таблиц с 1, 7 и 13 миллионами строк.
часто, когда в дискуссионных группах задаются вопросы о том, как выбрать случайные строки, предлагается запрос NEWID; он прост и очень хорошо работает для небольших таблиц.
SELECT TOP 10 PERCENT * FROM Table1 ORDER BY NEWID()однако запрос NEWID имеет большой недостаток, когда вы используете его для больших таблиц. Порядке, предусмотренном пунктом заставляет все строки в таблице должны быть скопированы в базе данных tempdb, где они сортируются. Это вызывает две проблемы:
- операция сортировки обычно имеет высокую стоимость, связанную с ней. Сортировка может использовать много дискового ввода/вывода и может работать в течение длительного времени.
- в худшем случае в базе данных tempdb может не хватить места. В в лучшем случае, база данных tempdb может занимать большой объем дискового пространства это никогда не будет исправлено без ручной команды сокращения.
что вам нужно, это способ выберите строки случайным образом, которые не будут использовать tempdb и не будет становиться намного медленнее, как таблица становится больше. Вот новая идея о том, как это сделать:
SELECT * FROM Table1 WHERE (ABS(CAST( (BINARY_CHECKSUM(*) * RAND()) as int)) % 100) < 10пожалуйста, прочитайте полную статью в MSDN.
это комбинация начальной идеи семени и контрольной суммы, которая, как мне кажется, дает правильные случайные результаты без стоимости NEWID ():
SELECT TOP [number] FROM table_name ORDER BY RAND(CHECKSUM(*) * RAND())
еще не совсем видел эту вариацию в ответах. У меня было дополнительное ограничение, когда мне нужно было, учитывая начальное семя, каждый раз выбирать один и тот же набор строк.
для MS SQL:
минимальный пример:
select top 10 percent * from table_name order by rand(checksum(*))нормированное время выполнения: 1.00
NewId () пример:
select top 10 percent * from table_name order by newid()нормированное время выполнения: 1.02
NewId()- это несущественно медленнее, чемrand(checksum(*)), так что вы не можете использовать его против большие наборы записей.выбор с начальным:
declare @seed int set @seed = Year(getdate()) * month(getdate()) /* any other initial seed here */ select top 10 percent * from table_name order by rand(checksum(*) % @seed) /* any other math function here */Если вам нужно выбрать тот же набор, учитывая семя, это, кажется, работает.
похоже, что newid () не может быть использован в предложении where, поэтому для этого решения требуется внутренний запрос:
SELECT * FROM ( SELECT *, ABS(CHECKSUM(NEWID())) AS Rnd FROM MyTable ) vw WHERE Rnd % 100 < 10 --10%
я использовал его в подзапросе, и он вернул мне те же строки в подзапросе
SELECT ID , ( SELECT TOP 1 ImageURL FROM SubTable ORDER BY NEWID() ) AS ImageURL, GETUTCDATE() , 1 FROM Mytableзатем я решил с включением переменной родительской таблицы в where
SELECT ID , ( SELECT TOP 1 ImageURL FROM SubTable Where Mytable.ID>0 ORDER BY NEWID() ) AS ImageURL, GETUTCDATE() , 1 FROM Mytableобратите внимание, где condtition
используемый язык обработки на стороне сервера (например, PHP, .net и т. д.) Не указан, но если это PHP, возьмите необходимое число (или все записи) и вместо рандомизации в запросе используйте функцию перемешивания PHP. Я не знаю, есть ли у .net эквивалентная функция, но если она есть, то используйте ее, если вы используете .net
ORDER BY RAND () может иметь довольно высокую производительность, в зависимости от того, сколько записей задействовано.
Comments