Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby where with find_each

I am looking at the official Rails documentation which shows how to use the "find_each" method. Here is an example they gave

Person.where("age > 21").find_each do |person|
  person.party_all_night!
end

This processes 1000 records at a time. However, I am still confused. How does this translate to SQL? What happens behind the scenes that allows Ruby to only process 1000 records at a time?

The reason I am sort of confused is because it seems Person.where("age > 21") would execute first, which would return ALL results.

For instance:

Person.where("age > 21").limit(10)

would return all persons in memory first, then give you the first 10, right?

like image 225
Henley Avatar asked Dec 05 '22 12:12

Henley


2 Answers

Person.where("age > 21") returns an ActiveRecord relation only. It doesn't return all the results.

Person.where("age > 21").limit(10) does NOT load all the models in memory, that would be awful and unusable. It just loads 10.

find_each doesn't really process 1000 records at a times. It loads 1000 records, and then process each one of them.

like image 109
Robin Avatar answered Dec 07 '22 00:12

Robin


I'd suggest running this from the console and looking at the SQL or reading the source code.

For example:

User.find_each(:batch_size => 40) do |user| end
  User Load (1.0ms)  SELECT "users".* FROM "users" WHERE ("users"."id" >= 0) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 96) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 156) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 219) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 272) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 314) ORDER BY "users"."id" ASC LIMIT 40
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE ("users"."id" > 355) ORDER BY "users"."id" ASC LIMIT 40

Or

bundle show activerecord
point your favorite code editor at that location and find the source
like image 23
John Naegle Avatar answered Dec 07 '22 02:12

John Naegle