10分ごとに約5000件のバックグラウンドジョブを実行しています。各ジョブは外部APIに対して要求を行い、データベース内の新規レコードを追加したり、既存のレコードを更新したりします。各API要求は約100個のアイテムを返します。したがって、10分ごとに50,000個のCREATEまたはUPDATE SQLクエリを作成しています。多くのレコードを一度にRailsで更新する
私がこれを処理する方法は、返される各APIアイテムに固有のIDがあります。このIDを持つ投稿をデータベースから検索し、存在する場合はモデルを更新します。それが存在しない場合は、新しいものを作成します。
APIレスポンスを想像してみては次のようになります。
class ParentModel < ApplicationRecord
def update
collection.each do |attrs|
child = ChildModel.find_or_initialize_by(external_id: attrs[:external_id], parent_model_id: self.id)
child.assign_attributes attrs
child.save if child.changed?
end
end
end
これらの各:私は私の親モデルでこのコードを実行後、変数collection
に設定されている
[
{
external_id: '123',
text: 'blah blah',
count: 450
},
{
external_id: 'abc',
text: 'something else',
count: 393
}
]
個々の通話は非常に速いですが、私が短期間に5万人をやっていると、実際にはそれが増え、減速する可能性があります。
私はこれを処理することができ、より効率的な方法があるのならば、私は次のように代わりに何かを考えていた思ったんだけど:
class ParentModel < ApplicationRecord
def update
eager_loaded_children = ChildModel.where(parent_model_id: self.id).limit(100)
collection.each do |attrs|
cached_child = eager_loaded_children.select {|child| child.external_id == attrs[:external_id] }.first
if cached_child
cached_child.update_attributes attrs
else
ChildModel.create attrs
end
end
end
end
基本的に私は、検索を保存し、代わりにフロントまで大きなクエリを実行することになります(これもかなり速いですが)メモリのトレードオフです。しかし、これはあまり時間がかかっているようには見えないかもしれませんが、ルックアップの部分を少しスピードアップするかもしれませんが、私はまだ100回更新して作成する必要があります。
私が考えていないバッチ更新を行う方法はありますか?これをもっと速くすることができる、または私がやっているクエリの量を減らすことができる他の明白な何か?
ああ大丈夫です。一度にすべての作成を行うというアイデアは間違いありません。私が問題であることを見いだすことができるのは、 'ChildModel.where(external_id:collection2.keys)'、 'collection2.keys'は潜在的に最大100個の鍵になる可能性があります。配列の多くのキー? – goddamnyouryan
私はそれが問題でなければならないとは思わないが、 'where'クエリで列の1000を取り出した。列が索引付けされていないかどうかは重要であろう。もし' external_id'を索引すると良いだろう。 –