Как мне взять эффективную простую случайную выборку в SQL? Рассматриваемая база данных работает под управлением MySQL; в моей таблице не менее 200 000 строк, и мне нужна простая случайная выборка из примерно 10 000.
«Очевидный» ответ:
SELECT * FROM table ORDER BY RAND() LIMIT 10000
Для больших таблиц это слишком медленно: он вызывает RAND()
каждую строку (которая уже помещает ее в O (n)) и сортирует их, делая в лучшем случае O (n lg n). Есть ли способ сделать это быстрее, чем O (n)?
Примечание . Как указывает Эндрю Мао в комментариях, если вы используете этот подход на SQL Server, вам следует использовать функцию T-SQL NEWID()
, потому что RAND () может возвращать одно и то же значение для всех строк .
РЕДАКТИРОВАТЬ: 5 ЛЕТ СПУСТЯ
Я снова столкнулся с этой проблемой с таблицей большего размера и в итоге использовал версию решения @ ignorant с двумя настройками:
- Сделайте выборку строк в 2-5 раз больше желаемого размера выборки, чтобы
ORDER BY RAND()
- Сохраняйте результат
RAND()
в индексированный столбец при каждой вставке / обновлении. (Если ваш набор данных не требует значительных обновлений, возможно, вам придется найти другой способ сохранить этот столбец в актуальном состоянии.)
Чтобы взять образец таблицы из 1000 элементов, я подсчитываю строки и отбираю результат в среднем до 10 000 строк со столбцом frozen_rand:
SELECT COUNT(*) FROM table; -- Use this to determine rand_low and rand_high
SELECT *
FROM table
WHERE frozen_rand BETWEEN %(rand_low)s AND %(rand_high)s
ORDER BY RAND() LIMIT 1000
(Моя реальная реализация требует дополнительной работы, чтобы убедиться, что я не недооцениваю выборку, и вручную обернуть rand_high, но основная идея - «случайным образом сократить число N до нескольких тысяч».)
Хотя это приносит некоторые жертвы, это позволяет мне выполнять выборку базы данных с помощью сканирования индекса, пока она снова не станет достаточно маленькой ORDER BY RAND()
.
RAND()
что каждый последующий вызов возвращает одно и то же значение.