2016-05-03 11 views
1

私は、ユーザが50kレコード以上、ノートが90kレコード以上の2つのテーブルusersnotesを持っています。私は私ができるの両方のテーブルのデータを持つことができる一時テーブルtemp_user_notesを作成しようとしていますRailsの巨大なテーブルからすべての行を効率的に取得する方法は?

id user_id created_at category impact_score 

users_tableの
class User < ActiveRecord::Base 
    has_many :notes 
end 

スキーマ:notes_tableの

id email created_at 

スキーマActiveRecordクエリを実行してデータを取得します。

user_notes_tableのスキーマ:

id user_id notes_id email user_created_at notes_created_at category impact_score 

私はすべての使用とそのノートをループこの

def self.populate_temp_user_notes 
    users = User.all 
    users.each do |user| 
     user.notes.each do |note| 
     user_notes = TempUserNote.new 
     user_notes.user_id = user.id 
     user_notes.notes_id = note.id 
     user_notes.auth_token_created_at = user.auth_token_created_at 
     user_notes.notes_recorded_at = note.recorded_at 
     user_notes.category = note.category 
     user_notes.well_being_score = note.perception_score 
     user_notes.save 
     end 
    end 
    end 

をしていますが、私は他にどのようなアプローチを使用することができ、プロセスを食べて非常に長いメモリのですか?ここから

EDIT: -

私の要件は次のとおりです。ユーザー、ノート、トランザクション、サブスクリプション:私はfolowingテーブルの使用を取るANDやOR条件で区切られた一連のクエリを持っています。ターゲットユーザを取得するクエリが(Query1 OR Query2) AND Query3 AND Query4 であると仮定した場合、各クエリの出力は次のクエリの入力となります。

例えば:私は私のターゲットユーザーを持っており、そこにノートの最後のユーザリストで

total users in DB = 1000 
1. user_list = (Query1 or Query2) #=> 500 users 
2. taking 500 users from user_list as input for next query 
3. user_list = user_list AND Query3 #=> 300 users 
4. taking 300 users from point 3 as input for query in point 4 
5. user_list = user_list AND Query4 #=> 50 users 

答えて

3

私は両方を減少させるfind_eachincludesの組み合わせを使用します。メモリ使用量とデータベースクエリの数:

def self.populate_temp_user_notes 
    User.includes(:notes).find_each do |user| 
    user.notes.each do |note| 
     TempUserNote.create(
     user_id:    user.id, 
     notes_id:    note.id, 
     auth_token_created_at: user.auth_token_created_at, 
     notes_recorded_at:  note.recorded_at, 
     category:    note.category, 
     well_being_score:  note.perception_score, 
    ) 
    end 
    end 
end 

もう一つの非常に高速なオプションは、このようなプレーンなSQLにしてこれを行うには次のようになります。

INSERT INTO temp_user_notes 
    (user_id, notes_id, auth_token_created_at, notes_recorded_at, category, well_being_score) 
    SELECT users.id, notes.id, users.auth_token_created_at, notes.recorded_at, notes.category, notes.perception_score 
    FROM users INNER JOIN notes ON users.id = notes.user_id; 
0

膨大な量のデータでは、User.allを使用することは決して有益ではありません。 50k行のデータを抽出し、各行に対して新しいオブジェクトUserを作成し、そのオブジェクトにその行のデータを移入するとします。はい、それはあなたのためのトラブルを作成するつもりです、そして、Railsはそれを認識しています。

あなたは使用することができます。

User.find_each do |user| 
    # do your thing 
end 

find_eachは、このようにメモリ操作を減らし、一度にあなたの1000年の記録を提供します。

あなたはfind_eachbatch_sizeを提供することにより、デフォルト値を上書きすることができます。

User.find_each(batch_size: 3000) do |user| 
    # do your thing 
end 
0

私が取得するために、私はActiveRecordのクエリを実行することができた上で両方のテーブルのデータを持つことができる一時表temp_user_notesを作成しようとしていますデータ。

もっと標準的な方法は、2つのテーブルを結合することです。。あなたは、次の句を使用する場合:

User.joins(:notes) 

が、これはあなたが、例えば缶(あなたにさらに照会のために使用することができる範囲を提供します例えば、両方のテーブルにwhere条件を追加)し、返されたレコードの両方UserNoteモデルから列が含まれます:

User.joins(:notes).where("notes.impact_score > 10") 

は一緒に接続しているユーザと、十分に高い得点であなたのすべてのノートを与えるだろう。

すべての結合レコードを処理する必要がある場合は、レコードをバッチ形式で返すfind_each methodを使用する必要があります。

+0

私は@BoraMaがジョインを使用することが効率的な方法であることに同意しますが、これを行うことは私の目的を解決しません。 私の要件は次のとおりです。ANDとOR条件で一連のクエリを分離しています。例:最後のユーザーのリストで 1. user_list =(Query1をまたはQUERY2) 2.入力 3. user_list = user_listとしてuser_list取ってQuery3 4. user_list = user_list(fulfillig条件3)AND Query4 私は私を持っていますターゲットユーザーとノートがあります。 – Prem

関連する問題