ActiveRecord를 통해 테이블에서 임의의 레코드를 가져와야합니다. 2006 년 Jamis Buck 의 예제를 따랐습니다 .
그러나 Google 검색을 통해 다른 방법으로 접근했습니다 (새로운 사용자 제한으로 인해 링크로 속성을 지정할 수 없음).
rand_id = rand(Model.count)
rand_record = Model.first(:conditions => ["id >= ?", rand_id])
나는 다른 사람들이 어떻게 그것을했는지 또는 누군가가 어떤 방법이 더 효율적인지 알고 있는지 궁금합니다.
답변
적어도 두 번의 쿼리 없이이 작업을 수행하는 이상적인 방법을 찾지 못했습니다.
다음은 임의로 생성 된 숫자 (현재 레코드 수까지)를 오프셋으로 사용 합니다.
offset = rand(Model.count)
# Rails 4
rand_record = Model.offset(offset).first
# Rails 3
rand_record = Model.first(:offset => offset)
솔직히 말하면 방금 데이터베이스에 따라 ORDER BY RAND () 또는 RANDOM ()을 사용하고 있습니다. 성능 문제가없는 경우 성능 문제가 아닙니다.
답변
레일 6
Jason의 의견에서 Rails 6에서는 비 속성 인수 는 허용되지 않습니다. Arel.sql()
명령문 에서 값을 랩해야합니다 .
Model.order(Arel.sql('RANDOM()')).first
레일 5, 4
에서는 레일 (4) 및 (5) 사용 PostgreSQL을 또는 SQLite는 사용 RANDOM()
:
Model.order('RANDOM()').first
아마도 MySQL 과 동일하게 작동합니다.RAND()
Model.order('RAND()').first
이것은 허용 된 답변 의 접근 방식보다 약 2.5 배 빠릅니다 .
주의 사항 : 수백만 개의 레코드가있는 대용량 데이터 세트의 경우 속도가 느리므로 limit
절 을 추가 할 수 있습니다 .
답변
레코드가 삭제되면 예제 코드가 부정확하게 작동하기 시작합니다 (ID가 낮은 항목은 부당하게 선호됩니다)
데이터베이스 내에서 임의의 방법을 사용하는 것이 좋습니다. 이것은 사용중인 DB에 따라 다르지만 : order => “RAND ()”는 mysql에서 작동하고 : order => “RANDOM ()”은 postgres에서 작동합니다.
Model.first(:order => "RANDOM()") # postgres example
답변
+5.1 만 레코드가있는 제품 테이블에서 MySQL 5.1.49, Ruby 1.9.2p180에서이 두 가지 방법을 벤치마킹하십시오.
def random1
rand_id = rand(Product.count)
rand_record = Product.first(:conditions => [ "id >= ?", rand_id])
end
def random2
if (c = Product.count) != 0
Product.find(:first, :offset =>rand(c))
end
end
n = 10
Benchmark.bm(7) do |x|
x.report("next id:") { n.times {|i| random1 } }
x.report("offset:") { n.times {|i| random2 } }
end
user system total real
next id: 0.040000 0.000000 0.040000 ( 0.225149)
offset : 0.020000 0.000000 0.020000 ( 35.234383)
MySQL의 오프셋은 훨씬 느려 보입니다.
편집
도 시도
Product.first(:order => "RAND()")
그러나 ~ 60 초 후에 그것을 죽여야했습니다. MySQL은 “디스크의 tmp 테이블에 복사”였습니다. 작동하지 않습니다.
답변
그렇게 열심히 할 필요는 없습니다.
ids = Model.pluck(:id)
random_model = Model.find(ids.sample)
pluck
테이블에있는 모든 ID의 배열을 반환합니다. sample
배열 의 메소드는 배열에서 임의의 ID를 반환합니다.
선택 가능성이 동일하고 삭제 된 행이있는 테이블을 지원하여 성능이 우수해야합니다. 제약 조건과 혼합 할 수도 있습니다.
User.where(favorite_day: "Friday").pluck(:id)
따라서 모든 사용자가 아닌 금요일을 좋아하는 임의의 사용자를 선택하십시오.
답변
당신이이 솔루션을 사용하는 것이 어떤 이유로 당신이 경우에, 그러나 것이 좋습니다되지 정말 하나의 데이터베이스 쿼리를하는 동안 무작위로 레코드를 선택하려면, 당신은 사용할 수 있습니다 sample
으로부터 방법을 루비 Array 클래스 는 임의의 항목을 선택할 수 있습니다, 배열에서.
Model.all.sample
이 방법은 데이터베이스 쿼리 만 필요하지만 Model.offset(rand(Model.count)).first
두 데이터베이스 쿼리가 필요한 대안보다 훨씬 느리지 만 후자는 여전히 선호됩니다.
답변
나는 이것을 처리하기 위해 레일 3 보석을 만들었습니다.
https://github.com/spilliton/randumb
다음과 같은 작업을 수행 할 수 있습니다.
Model.where(:column => "value").random(10)