ruby on rails - Are you allowed to use a find_each query with an includes statement? -
example:
foobar.joins(:baz).includes(:baz).count => 22926 foobar.joins(:baz).includes(:baz).find_each.count => 998 foobar.joins(:baz).find_each.count => 22926   the generated sql in correct case (third) several batches of sql looks like:
select  "foobar".* "foobar" inner join "baz" on  "baz"."foobar_id" = "foobar"."id" order "foobar"."id" asc limit $1   in failing (second) case there single query looks like:
select  "foobar"."id" t0_r0  "baz"."id" t1_r0  "baz"."foobar_id" t1_r1  "foobar" inner join "baz" on "baz"."foobar_id" = "foobar"."id"   order "foobar"."id" asc limit $1   where of fields listed different temporary variable (e.g. t0_r0) different columns on each table (in actual query there 37 split 30 on first object, 7 on second). 
is bug? includes not allowed in find_each query? doing wrong?
the relationship between foobar , baz foobar has_one baz , baz belongs_to foobar.
this problem can happen if has_one relationship isn't has_one.
say database doesn't have unique index on column baz.foobar_id.  accidentally end situation have foobar record connected more 1 baz record:
baz.id | baz.foobar_id ------   ------------- 1        1 2        1 3        2   in situation, joins return combination of foobar , baz records:
foobar.joins(:baz).count  # 3   this means find_each join iterate 3 times , repeat 1 of foobar ids:
foobar.joins(:baz).find_each(batch_size: 2) { |f| puts f.id } # select  "foobar".* "foobar" inner join "baz" on... limit 2 1 1 # select  "foobar".* "foobar" inner join "baz" on... ("foobar"."id" > 1) ... limit 2 2   adding in includes means rails going try consolidate results set of distinct foobar records.  won't work how find_each manages batches:
foobar.joins(:baz).includes(:baz).find_each(batch_size: 2) { |f| puts f.id } # select  "foobar"."id" t0_r0 ... limit 2 1   and @ point find_each stop processing because has found batch smaller batch size, thinks done:
# activerecord::batches#in_batches break if ids.length < batch_limit   the default batch size find_each 1,000.  problem case returned 998 records.  indicates first batch loaded 998 unique foobar ids less batch size, , find_each thought done.  loaded 1,000 baz records connected 998 distinct foobar records.
you may want review baz table see if has duplicate entries.  can like:
baz.group(:foobar_id).having('count(*) > 1')   the best solution use unique index avoid duplicates in database , enforce has_one relationship.  alternative ensure you're getting distinct set of foobar records like:
foobar.group(:id).joins(:baz).includes(:baz).count foobar.group(:id).joins(:baz).includes(:baz).find_each.count foobar.group(:id).joins(:baz).find_each.count      
Comments
Post a Comment