5

私は(私の見解では):

# myUser is a User in ActiveRecord with :has_many :posts
myUser.posts.each do |post|
end

ユーザーが 10 件の投稿をした場合、これはデータベース呼び出しを 10 回行うことになりますか? これらのループは次のようにする必要がありますか?:

myPosts = myUser.posts
myPosts.each do |post|
end

これは、テストのために行ったruby​​ ファイルのペースト ビンです。編集貼り付けビンを変更しました。

これはJavaのコードを思い出させます

for (int i = 0; i < someExpensiveFunction(); i++)

そうあるべきです(配列が変更されない限り)

for (int i = 0, len=someExpensiveFunction(); i < len; i++)

何か不足していますか?has_many人々がオブジェクトのフィールドをループするレールの例がたくさんあります。これは、アプリケーションのパフォーマンスを最適化しようとしている私にとって重要です。

4

1 に答える 1

10

ユーザーが 10 件の投稿をした場合、これは技術的にデータベース呼び出しを 10 回行うことになりますか?

いいえ。

myUser = User.find 123
myUser.posts.each do |post|
  puts post.title
end

このコードは、2 つのクエリを実行します。1 つ目は ID でユーザーを検索し、単一の行を返します。2 つ目は、一致するユーザー ID を持つすべての投稿を求めるクエリを実行しますmyUser。次に、eachその結​​果を使用して反復します。


開発モードでログを見ると、実行中のクエリが表示され、それらすべての投稿を返す単一のクエリが表示されるはずです。

Rails は関連付けプロキシ オブジェクトを使用してクエリを保持し、レコードが必要なときにクエリを実行して、結果をキャッシュします。これは非常に役立つコードであり、ほとんどの場合、このようなことを処理します。

これはRuby ではなくRailsの機能です。


ruby レベルでは、each単にコレクションに作用します。

def get_letters
  puts 'executing "query"'
  sleep(3)
  ["a","b","c"]
end

get_letters.each do |item|
  puts item
end

これは印刷されるはずです。

executing "query"
a
b
c

get_lettersメソッドが実行されると、配列が返されます。この配列には、既にデータが格納されているため、メソッドを呼び出して、各eachアイテムを処理できます。コレクションのフェッチと反復処理は、2 つの完全に別個のステップです。


ペーストビンから:

# will this run forever?
myArr = ["a","b","c"]
myArr.each do |item|
  myArr.push("x")
end

ええ、そうなりますが、配列がオーバーオーバーで「フェッチ」されているためではありません。

これは、このような JavaScript と同等であり、より適切に綴られています。

myArr = ["a","b","c"];
for (var i = 0; i < myArr.length; i++) {
  myArr.push('x');
}

元の配列は、ループの各反復で、まだ完了しているかどうかを確認します。しかし、配列はアイテムが 1 つ進むたびに 1 つ長くなるため、反復ごとに両方が 1 つ増加するため、i < myArr.length常に長くなります。同じ理由で、trueあなたのループでルビーでも同じことが起こっています。each

配列を再生成するためにいくつかのコードを実行し続けるためではなく、永久に実行されます。結果の配列を人為的に変更しているため、永久に実行されます。

于 2012-12-04T18:41:50.077 に答える