.order('RANDOM()').limit(limit)
выглядит аккуратно, но медленно для больших таблиц, потому что ему нужно извлекать и сортировать все строки, даже если limit
равен 1 (внутренне в базе данных, но не в Rails). Я не уверен насчет MySQL, но это происходит в Postgres. Больше объяснений в здесь и здесь .
Одним из решений для больших таблиц является .from("products TABLESAMPLE SYSTEM(0.5)")
, где 0.5
означает 0.5%
. Тем не менее, я считаю, что это решение все еще медленно, если у вас есть условия WHERE
, которые отфильтровывают много строк. Я думаю, это потому, что TABLESAMPLE SYSTEM(0.5)
извлекает все строки до применения WHERE
условий.
Другое решение для больших таблиц (но не очень случайное):
products_scope.limit(sample_size).sample(limit)
, где sample_size
может быть 100
(но не слишком большим, иначе он медленный и занимает много памяти), а limit
может быть 1
. Обратите внимание, что, хотя это быстро, но на самом деле не случайно, оно случайно только в sample_size
записях.
PS: результаты тестов в ответах выше не являются надежными (по крайней мере, в Postgres), поскольку некоторые запросы к БД, выполняющиеся во 2-й раз, могут быть значительно быстрее, чем в 1-й раз, благодаря кешу БД. И, к сожалению, в Postgres нет простого способа отключить кеш, чтобы сделать эти тесты надежными.