.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 нет простого способа отключить кэш, чтобы сделать эти тесты надежными.