Я снова столкнулся с проблемой выбора случайного подмножества строк. И, как многие, вероятно, знают, ORDER BY RAND () довольно неэффективен, или, по крайней мере, это консенсус. Я прочитал, что mysql генерирует случайные значения для каждой строки в таблице, затем фильтрует, затем упорядочивает по этим случайным значениям, а затем возвращает множество. Наибольшее влияние на производительность, по-видимому, оказывает тот факт, что генерируется столько же случайных чисел, сколько строк в таблице. Поэтому я искал, возможно, лучший способ вернуть случайное подмножество результатов для такого запроса:
SELECT id FROM <table> WHERE <some conditions> LIMIT 10;
Конечно, самый простой и легкий способ сделать то, что я хочу, - это одна ведьма, которую я стараюсь избегать:
SELECT id FROM <table> WHERE <some conditions> ORDER BY RAND() LIMIT 10; (a)
Теперь, подумав, я предложил другой вариант для этой задачи:
SELECT id FROM <table> WHERE (<some conditions>) AND RAND() > x LIMIT 10; (b)
(Конечно, мы можем использовать <
вместо >
). Здесь мы берем x
из диапазона 0.0 - 1.0
. Теперь я не совсем уверен, как MySQL справляется с этим, но я предполагаю, что сначала он выбирает строки, соответствующие <some conditions>
(используя index [es]?), А затем генерирует случайное значение и видит, должен ли он возвращать или отбрасывать строку. Но что я знаю :) вот почему я спрашиваю здесь. Итак, некоторые наблюдения об этом методе:
- Во-первых, это не гарантирует, что запрашиваемое количество строк будет возвращено, даже если совпадающих строк будет намного больше, чем необходимо, особенно это верно для
x
значений, близких к 1.0
(или близких к 0.0
, если мы используем <
) * * тысяча двадцать-два
- возвращенный объект на самом деле не имеет случайного порядка, это просто объекты, выбранные случайным образом, по порядку использованного индекса или по тому, как они хранятся (?) (Конечно, в некоторых случаях это может вообще не иметь значения)
- нам, вероятно, нужно выбрать
x
в соответствии с размером набора результатов, поскольку, если у нас большой набор результатов и x
, скажем, 0.1
, очень вероятно, что будут возвращены только некоторые случайные первые результаты. большую часть времени; с другой стороны, если у вас небольшой набор результатов и вы выбрали большой x
, вполне вероятно, что мы могли бы получить меньше объектов, чем нам хотелось бы, хотя их достаточно
Теперь несколько слов о производительности. Я провел небольшое тестирование с использованием jmeter. <table>
имеет около 20 тыс. Строк, и примерно 2-3 тыс. Строк соответствуют 1034 *. Я написал простой PHP-скрипт, который выполняет запрос и print_r
- результат. Затем я настраиваю тест с использованием jmeter, который запускает 200 потоков, то есть 200 запросов в секунду, и запрашивает указанный скрипт PHP. Я запускал его до тех пор, пока не было выполнено около 3 000 запросов (среднее время ответа стабилизировалось задолго до этого). Также я выполнил все запросы с SQL_NO_CACHE
, чтобы предотвратить какой-либо эффект кеша запросов. Среднее время ответа было:
- ~ 30 мс для запроса (а)
- 13-15 мс для запроса (b) с
x = 0.1
- 17-20 мс для запроса (b) с
x = 0.9
, как ожидается, большее значение x
медленнее, так как должно отбрасывать больше строк
Итак, мои вопросы: что вы думаете об этом методе выбора случайных строк? Может быть, вы использовали это или попробовали и видите, что это не сработало? Может быть, вы можете лучше объяснить, как MySQL обрабатывает такой запрос? Какие могут быть некоторые оговорки, о которых я не знаю?
РЕДАКТИРОВАТЬ: Я, вероятно, не был достаточно ясен, дело в том, что мне нужны случайные строки запроса, а не просто таблица, поэтому я включил <some conditions>
, и их довольно много. Более того, в таблице гарантированно есть пропуски в id, но это не имеет большого значения, поскольку это не случайные строки из таблицы, а из запроса, и таких запросов будет довольно много, поэтому предложения, включающие многократное обращение к таблице, не звучат привлекательно. <some conditions>
будет меняться, по крайней мере, немного между запросами, что означает, что будут запросы с различными условиями.