Я занимаюсь некоторыми исследованиями и тестированием того, как сделать быстрый случайный выбор в MySQL. В процессе я столкнулся с некоторыми неожиданными результатами, и теперь я не совсем уверен, что знаю, как работает ORDER BY RAND().
Я всегда думал, что когда вы делаете ORDER BY RAND() в таблице, MySQL добавляет новый столбец в таблицу, заполненную случайными значениями, затем сортирует данные по этому столбцу, а затем, например, вы берете вышеуказанное значение, которое попало туда случайно. Я сделал много поиска и тестирования и, наконец, нашел, что запрос Jay предлагает в своем блоге - самое быстрое решение:
SELECT * FROM Table T JOIN (SELECT CEIL(MAX(ID)*RAND()) AS ID FROM Table) AS x ON T.ID >= x.ID LIMIT 1;
В то время как обычный ORDER BY RAND() занимает 30-40 секунд в моей тестовой таблице, его запрос выполняет работу за 0,1 секунды. Он объясняет, как это работает в блоге, поэтому я просто пропущу это и, наконец, перейду к странной вещи.
Моя таблица является общей таблицей с PRIMARY KEY id
и другими неиндексированными материалами вроде username
, age
и т.д. Вот что я боюсь объяснить
SELECT * FROM table ORDER BY RAND() LIMIT 1; /*30-40 seconds*/
SELECT id FROM table ORDER BY RAND() LIMIT 1; /*0.25 seconds*/
SELECT id, username FROM table ORDER BY RAND() LIMIT 1; /*90 seconds*/
Я как бы ожидал увидеть примерно одно и то же время для всех трех запросов, так как я всегда сортирую по одному столбцу. Но почему-то этого не произошло. Пожалуйста, дайте мне знать, если у вас есть идеи об этом. У меня есть проект, где мне нужно быстро выполнить ORDER BY RAND(), и лично я предпочел бы использовать
SELECT id FROM table ORDER BY RAND() LIMIT 1;
SELECT * FROM table WHERE id=ID_FROM_PREVIOUS_QUERY LIMIT 1;
который, да, медленнее, чем метод Джей, однако он меньше и легче понять. Мои запросы довольно большие с несколькими JOIN и с предложением WHERE, и в то время как метод Jay все еще работает, запрос становится действительно большим и сложным, потому что мне нужно использовать все JOIN и WHERE в запросе sub-запроса JOINed (так называемый x в его запросе).
Спасибо за ваше время!