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