따라서 Rails 2에서 무작위 레코드를 찾는 몇 가지 예를 찾았습니다. 선호하는 방법은 다음과 같습니다.
Thing.find :first, :offset => rand(Thing.count)
초보자의 무언가이기 때문에 Rails 3의 새로운 찾기 구문을 사용하여 어떻게 구성 할 수 있는지 잘 모르겠습니다.
랜덤 레코드를 찾는 "Rails 3 Way"는 무엇입니까?
따라서 Rails 2에서 무작위 레코드를 찾는 몇 가지 예를 찾았습니다. 선호하는 방법은 다음과 같습니다.
Thing.find :first, :offset => rand(Thing.count)
초보자의 무언가이기 때문에 Rails 3의 새로운 찾기 구문을 사용하여 어떻게 구성 할 수 있는지 잘 모르겠습니다.
랜덤 레코드를 찾는 "Rails 3 Way"는 무엇입니까?
답변:
Thing.first(:order => "RANDOM()") # For MySQL :order => "RAND()", - thanx, @DanSingerman
# Rails 3
Thing.order("RANDOM()").first
또는
Thing.first(:offset => rand(Thing.count))
# Rails 3
Thing.offset(rand(Thing.count)).first
실제로 Rails 3에서는 모든 예제가 작동합니다. 그러나 RANDOM큰 테이블의 경우 순서를 사용하는 것이 상당히 느리지 만 더 SQL 스타일
UPD. 인덱스 열에서 다음과 같은 트릭을 사용할 수 있습니다 (PostgreSQL 구문).
select *
from my_table
where id >= trunc(
random() * (select max(id) from my_table) + 1
)
order by id
limit 1;
RAND()또는 RANDOM()입니다. 감사합니다
DB가 localhost에 있고 users 테이블에 100K 개 이상의 레코드 가있는 프로젝트 ( Rails 3.0.15, ruby 1.9.3-p125-perf )를 작업 중입니다. 입니다.
사용
RAND ()로 주문
꽤 느리다
User.order ( "RAND (id)"). first
된다
RAND (ID) 제한으로 주문
users. *에서 선택users1
로부터 얻어 8 행 12 초응답 에서 !!
레일스 로그 :
사용자로드 (11030.8ms) 선택
users. *usersRAND () 제한 순서 1
MySQL의 설명에서
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 110165 | Using temporary; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+--------+---------------------------------+
인덱스가 사용되지 않고 ( possible_keys = NULL ), 임시 테이블이 생성되고 원하는 값을 가져 오기 위해 추가 패스가 필요함을 알 수 있습니다 ( extra = 임시 사용; 파일 정렬 사용 ).
반면 쿼리를 두 부분으로 나누고 Ruby를 사용하면 응답 시간이 상당히 향상됩니다.
users = User.scoped.select(:id);nil
User.find( users.first( Random.rand( users.length )).last )
(; 콘솔 사용에는 없음)
레일스 로그 :
사용자로드 (25.2ms) SELECT id FROM
users사용자로드 (0.2ms) SELECTusers. * FROMusersWHEREusers.id= 106854 제한 1
그리고 mysql의 설명은 이유를 증명합니다 :
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
| 1 | SIMPLE | users | index | NULL | index_users_on_user_type | 2 | NULL | 110165 | Using index |
+----+-------------+-------+-------+---------------+--------------------------+---------+------+--------+-------------+
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+
이제 인덱스와 기본 키만 사용할 수 있으며 약 500 배 빠르게 작업을 수행 할 수 있습니다!
최신 정보:
주석에서 icantbecool이 지적한 것처럼 위의 솔루션에는 테이블에 삭제 된 레코드가 있으면 결함이 있습니다.
그 해결 방법은 다음과 같습니다.
users_count = User.count
User.scoped.limit(1).offset(rand(users_count)).first
두 개의 쿼리로 변환됩니다
SELECT COUNT(*) FROM `users`
SELECT `users`.* FROM `users` LIMIT 1 OFFSET 148794
약 500ms에서 실행됩니다.
RAND(id)것 NOT 다른 임의의 순서로 당신에게 모든 쿼리를 제공합니다. RAND()쿼리마다 다른 순서를 원하면 사용하십시오 .
Postgres를 사용하는 경우
User.limit(5).order("RANDOM()")
MySQL을 사용하는 경우
User.limit(5).order("RAND()")
두 경우 모두 Users 테이블에서 무작위로 5 개의 레코드를 선택합니다. 다음은 콘솔에 표시되는 실제 SQL 쿼리입니다.
SELECT * FROM users ORDER BY RANDOM() LIMIT 5
큰 테이블에서 더 잘 수행하고 관계와 범위를 연결할 수 있도록 레일 3 gem을 만들었습니다.
https://github.com/spilliton/randumb
(편집) : 내 보석의 기본 동작은 기본적으로 위와 동일한 접근법을 사용하지만 원하는 경우 이전 방식을 사용할 수 있습니다. :)
게시 된 많은 답변이 실제로 큰 테이블 (1 + 백만 행)에서 제대로 수행되지 않습니다. 임의 순서는 빠르게 몇 초가 걸리고 테이블에서 계산을 수행하는 데에도 시간이 오래 걸립니다.
이 상황에서 나에게 잘 맞는 해결책 RANDOM()은 where 조건과 함께 사용 하는 것입니다.
Thing.where('RANDOM() >= 0.9').take
백만 개가 넘는 행이있는 테이블에서이 쿼리는 일반적으로 2ms 미만이 소요됩니다.
take은 LIMIT(1)쿼리 를 제공 하지만 배열 대신 단일 요소를 반환 하는 함수를 사용 한다는 것입니다. 따라서 우리는 호출 할 필요가 없습니다first
여기 우리는 간다
#in your initializer
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
Model.random #returns single random object
아니면 두번째 생각은
module ActiveRecord
class Base
def self.random
order("RAND()")
end
end
end
용법:
Model.random #returns shuffled collection
Couldn't find all Users with 'id': (first, {:offset=>1}) (found 0 results, but was looking for 2)
"RANDOM()"대신 사용할 수 있습니다 .
이것은 나에게 매우 유용했지만 좀 더 융통성이 필요했기 때문에 이것이 내가 한 일입니다.
사례 1 : 하나의 무작위 레코드 소스 찾기 : 트레버 터크 사이트
Thing.rb 모델에 추가
def self.random
ids = connection.select_all("SELECT id FROM things")
find(ids[rand(ids.length)]["id"].to_i) unless ids.blank?
end
그런 다음 컨트롤러에서 다음과 같이 호출 할 수 있습니다
@thing = Thing.random
사례 2 : 여러 개의 무작위 레코드 찾기 (반복 없음) 출처 : 반복 하지 않고
10 개의 무작위 레코드를 찾아야했기 때문에 이것이
컨트롤러 에서 작동하는 것을 기억 합니다.
thing_ids = Thing.find( :all, :select => 'id' ).map( &:id )
@things = Thing.find( (1..10).map { thing_ids.delete_at( thing_ids.size * rand ) } )
이것은 10 개의 무작위 레코드를 찾을 수 있지만, 데이터베이스가 특히 큰 경우 (수백만 개의 레코드) 이것이 이상적이지 않으며 성능이 저하 될 것임을 언급 할 가치가 있습니다. 나에게 충분한 수천 개의 기록을 잘 수행 할 것입니다.
목록에서 항목을 임의로 선택하는 Ruby 방법은 sample입니다. sampleActiveRecord를 효율적으로 만들고 싶었고 이전 답변을 바탕으로 다음을 사용했습니다.
module ActiveRecord
class Base
def self.sample
offset(rand(size)).first
end
end
end
이것을 넣고 lib/ext/sample.rb다음과 같이로드하십시오 config/initializers/monkey_patches.rb:
Dir[Rails.root.join('lib/ext/*.rb')].each { |file| require file }
#count에 대한 DB 호출을 수행합니다 COUNT. 레코드가 이미로드 된 경우 이는 나쁜 생각 일 수 있습니다. 리 팩터는 #size대신 사용 #count해야하는지 또는 레코드가 이미로드되어 있는지를 결정하기 때문에 대신 사용 하는 것 #length입니다.
Rails 5에서 작동하며 DB에 독립적입니다.
이것은 컨트롤러에서 :
@quotes = Quote.offset(rand(Quote.count - 3)).limit(3)
module Randomable
extend ActiveSupport::Concern
class_methods do
def random(the_count = 1)
records = offset(rand(count - the_count)).limit(the_count)
the_count == 1 ? records.first : records
end
end
end
그때...
class Book < ActiveRecord::Base
include Randomable
end
그런 다음 다음을 수행하여 간단히 사용할 수 있습니다.
Books.random
또는
Books.random(3)
ActiveRecord에서 sample ()을 사용할 수 있습니다
예 :
def get_random_things_for_home_page
find(:all).sample(5)
end
출처 : http://thinkingeek.com/2011/07/04/easily-select-random-records-rails/
sampleActiveRecord에없고 샘플이 배열에 있습니다. api.rubyonrails.org/classes/Array.html#method-i-sample
Oracle을 사용하는 경우
User.limit(10).order("DBMS_RANDOM.VALUE")
산출
SELECT * FROM users ORDER BY DBMS_RANDOM.VALUE WHERE ROWNUM <= 10
많은 데이터 행이있는 테이블을 위해 특별히 설계된 임의 레코드에 대해이 gem을 강력하게 권장합니다.
https://github.com/haopingfan/quick_random_records
이 gem을 제외하고 다른 모든 답변은 큰 데이터베이스에서 제대로 수행되지 않습니다.
4.6ms총 비용 입니다.User.order('RAND()').limit(10)비용 733.0ms.offset접근 방식은 비용이 245.4ms완전히.User.all.sample(10)접근 비용 573.4ms.참고 : 내 테이블에는 120,000 명의 사용자 만 있습니다. 기록이 많을수록 성능 차이가 더 커집니다.
최신 정보:
550,000 개의 행이있는 테이블에서 수행
Model.where(id: Model.pluck(:id).sample(10)) 비용 1384.0msgem: quick_random_records6.4ms완전히 비용테이블에서 여러 개의 무작위 레코드를 얻는 매우 쉬운 방법입니다. 이렇게하면 2 개의 저렴한 쿼리가 만들어집니다.
Model.where(id: Model.pluck(:id).sample(3))
"3"을 원하는 임의의 레코드 수로 변경할 수 있습니다.
방금 DB에서 무작위 질문을 선택하려는 작은 응용 프로그램을 개발하는이 문제에 부딪 쳤습니다. 나는 사용했다 :
@question1 = Question.where(:lesson_id => params[:lesson_id]).shuffle[1]
그리고 그것은 나를 위해 잘 작동합니다. 더 큰 DB의 성능이 작은 응용 프로그램이므로 어떻게 큰 DB의 성능에 대해 말할 수 없습니다.
shuffle[0])