복붙노트

[RUBY-ON-RAILS] 3 레일 : 임의의 레코드를 가져

RUBY-ON-RAILS

3 레일 : 임의의 레코드를 가져

그래서, 레일 2 임의의 기록을 찾기 위해 몇 가지 예를 발견했습니다 - 선호되는 방법은 것 같다 :

Thing.find :first, :offset => rand(Thing.count)

초보자의 일이기 때문에 나는이 레일 3의 새 발견 구문을 사용하여 구성 할 수있는 방법을 모르겠어요.

따라서, 임의의 기록을 찾을 수있는 "레일 3 자"는 무엇인가요?

해결법

  1. ==============================

    1.

    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
    

    사실, 레일 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;
    
  2. ==============================

    2.DB를 로컬 호스트에있는 사용자 테이블이 조금 이상 100K 레코드가 어디 프로젝트를 진행하고있다 (1.9.3-P125-반환 한 루비, 3.0.15 레일).

    DB를 로컬 호스트에있는 사용자 테이블이 조금 이상 100K 레코드가 어디 프로젝트를 진행하고있다 (1.9.3-P125-반환 한 루비, 3.0.15 레일).

    사용

    아주 느린

    가된다

    및 응답에 8 ~ 12 초 정도 소요!

    레일 로그 :

    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), 임시 테이블이 생성되고 추가 패스가 원하는 값 가져 오기 위해 필요하다 (임시 사용하여 추가 =을, filesort를 사용).

    반면에, 분할에 의해 두 부분으로 루비를 사용에서 쿼리, 우리는 응답 시간의 합리적인 개선이있다.

    users = User.scoped.select(:id);nil
    User.find( users.first( Random.rand( users.length )).last )
    

    (; 콘솔 사용하기위한 무기 호)

    레일 로그 :

    과의 설명 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에 대해 실행됩니다.

  3. ==============================

    3.포스트 그레스를 사용하는 경우

    포스트 그레스를 사용하는 경우

    User.limit(5).order("RANDOM()")
    

    MySQL을 사용하는 경우

    User.limit(5).order("RAND()")
    

    두 경우 모두 사용자는 사용자 테이블에서 무작위로 5 개 기록을 선택하고 있습니다. 다음은 콘솔에 표시에서 실제 SQL 쿼리입니다.

    SELECT * FROM users ORDER BY RANDOM() LIMIT 5
    
  4. ==============================

    4.나는 더 큰 테이블에 수행하는이 일을 위해 3 보석 레일 체인 관계에 당신을 허용하고 스코프했다 :

    나는 더 큰 테이블에 수행하는이 일을 위해 3 보석 레일 체인 관계에 당신을 허용하고 스코프했다 :

    https://github.com/spilliton/randumb

    (편집) : 내 보석의 기본 동작은 기본적으로 현재 상기와 동일한 방법을 사용하지만, 당신은 당신이 원하는 경우 기존의 방법을 사용할 수있는 옵션이 있습니다 :

  5. ==============================

    5.답변의 대부분은 오히려 큰 테이블 (1 + 백만 행)을 잘 수행하지 않습니다 실제로 기록했다. 임의의 순서는 빠르게 몇 초 정도 소요되며, 테이블에 계산을 수행하는 것은 상당히 오래 걸립니다.

    답변의 대부분은 오히려 큰 테이블 (1 + 백만 행)을 잘 수행하지 않습니다 실제로 기록했다. 임의의 순서는 빠르게 몇 초 정도 소요되며, 테이블에 계산을 수행하는 것은 상당히 오래 걸립니다.

    이 상황에서 나를 위해 잘 작동하는 솔루션은 어디서 A 조건으로 RANDOM ()를 사용하는 것입니다 :

    Thing.where('RANDOM() >= 0.9').take
    

    만 이상의 열이있는 테이블에서이 쿼리는 일반적으로 2ms의 채 걸리지 않습니다.

  6. ==============================

    6.우리가 여기 요

    우리가 여기 요

    #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
    
  7. ==============================

    7.이 내가 무슨 짓을했는지, 그래서 이것은, 그러나 내가 좀 더 유연성을 필요로 나에게 매우 유용했다 :

    이 내가 무슨 짓을했는지, 그래서 이것은, 그러나 내가 좀 더 유연성을 필요로 나에게 매우 유용했다 :

    사례 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
    

    Case2 : 여러 무작위 기록 (반복없이) 소스를 찾기 : 기억이 안나요 이 내가 일을 찾았는지, 그래서 나는 반복없이 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 개 임의 기록을 찾을 수 및 성능이 방해 될 것입니다. 나를 위해 충분했다 수천 레코드를 잘 수행입니다.

  8. ==============================

    8.무작위로 목록에서 항목을 따기위한 루비 방법은 샘플입니다. 액티브위한 효율적인 샘플을 만들 싶은, 이전 응답에 따라, 내가 사용 :

    무작위로 목록에서 항목을 따기위한 루비 방법은 샘플입니다. 액티브위한 효율적인 샘플을 만들 싶은, 이전 응답에 따라, 내가 사용 :

    module ActiveRecord
      class Base
        def self.sample
          offset(rand(size)).first
        end
      end
    end
    

    나는이에 lib 디렉토리 / 내선 / sample.rb 다음이에서 설정 / 초기화 / monkey_patches.rb로로드 넣어 :

    Dir[Rails.root.join('lib/ext/*.rb')].each { |file| require file }
    
  9. ==============================

    9.레일 5 작동 및 DB 불가지론이다 :

    레일 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)
    
  10. ==============================

    10.당신은 액티브에 샘플을 ()를 사용할 수 있습니다

    당신은 액티브에 샘플을 ()를 사용할 수 있습니다

    EG

    def get_random_things_for_home_page
      find(:all).sample(5)
    end
    

    출처 : http://thinkingeek.com/2011/07/04/easily-select-random-records-rails/

  11. ==============================

    11.오라클을 사용하는 경우

    오라클을 사용하는 경우

    User.limit(10).order("DBMS_RANDOM.VALUE")
    

    산출

    SELECT * FROM users ORDER BY DBMS_RANDOM.VALUE WHERE ROWNUM <= 10
    
  12. ==============================

    12.강력 특별히 데이터 행이 많은 테이블을 위해 설계 임의 기록이 보석을, 추천 :

    강력 특별히 데이터 행이 많은 테이블을 위해 설계 임의 기록이 보석을, 추천 :

    https://github.com/haopingfan/quick_random_records

    모든 다른 답변이 보석을 제외하고 대형 데이터베이스와 심하게 수행

    참고 : 내 테이블은 12 만 사용자를 가지고있다. 당신이 더 많은 기록은 성능의 더 엄청난 차이가있을 것입니다.

    최신 정보:

    550,000 행이 테이블에 수행

  13. ==============================

    13.아주 쉬운 방법은 테이블에서 여러 무작위 기록을 얻을 수 있습니다. 이것은이 싼 쿼리를합니다.

    아주 쉬운 방법은 테이블에서 여러 무작위 기록을 얻을 수 있습니다. 이것은이 싼 쿼리를합니다.

    Model.where (ID : Model.pluck (: ID) .sample (3))

    당신은 당신이 원하는 임의의 레코드 수에 "3"을 변경할 수 있습니다.

  14. ==============================

    14.난 그냥 내 DB에서 무작위로 질문을 선택하고 싶어 작은 응용 프로그램을 개발하고이 문제에 달렸다. 내가 사용 :

    난 그냥 내 DB에서 무작위로 질문을 선택하고 싶어 작은 응용 프로그램을 개발하고이 문제에 달렸다. 내가 사용 :

    @question1 = Question.where(:lesson_id => params[:lesson_id]).shuffle[1]
    

    그리고 그것은 나를 위해 잘 작동합니다. 나는이 이후 더 큰 DB에 대한 성능이 단지 작은 응용 프로그램입니다 방법에 대해 말할 수 없다.

  15. from https://stackoverflow.com/questions/5342270/rails-3-get-random-record by cc-by-sa and MIT license