2017-04-07 36 views
4

例如:您是否允许使用包含语句的find_each查询?

Foobar.joins(:baz).includes(:baz).count 
=> 22926 
Foobar.joins(:baz).includes(:baz).find_each.count 
=> 998 
Foobar.joins(:baz).find_each.count 
=> 22926 

在正确的情况下(第三)生成的SQL是SQL,看起来像的几个批次:

SELECT "foobar".* FROM "foobar" INNER JOIN "baz" ON 
"baz"."foobar_id" = "foobar"."id" ORDER BY "foobar"."id" ASC LIMIT $1 
在失败

(第二)的情况下有一个单一的查询看起来像:

SELECT "foobar"."id" AS t0_r0 
"baz"."id" AS t1_r0 
"baz"."foobar_id" AS t1_r1 
FROM "foobar" INNER JOIN "baz" ON "baz"."foobar_id" = "foobar"."id" 
ORDER BY "foobar"."id" ASC LIMIT $1 

其中所有字段都列为关于电子的不同列的不同的临时变量(例如t0_r0) ach表(在实际查询中,第一个对象上有37个分割的30个,第二个对象上有7个)。

这是一个错误? includes不允许在find_each查询中被允许吗?难道我做错了什么?

FoobarBaz之间的关系是Foobarhas_oneBazBazbelongs_toFoobar

+0

你使用的是什么Rails版本? –

+0

我正在使用Rails 5.0.2 –

回答

1

如果您的has_one关系不是真的has_one,则可能会发生此问题。

假定您的数据库在列baz.foobar_id上没有唯一索引。然后,你可能会不小心与这样的情况下结束了,你必须连接到一个以上的巴兹记录一个Foobar的记录:

baz.id | baz.foobar_id 
------ ------------- 
1  1 
2  1 
3  2 

在这种情况下,joins将返回的Foobar和巴兹记录的组合:

Foobar.joins(:baz).count # This would be 3 

这也意味着,find_eachjoin会重复3次,重复Foobar的ID之一:

Foobar.joins(:baz).find_each(batch_size: 2) { |f| puts f.id } 
# SELECT "foobar".* FROM "foobar" INNER JOIN "baz" ON... LIMIT 2 
1 
1 
# SELECT "foobar".* FROM "foobar" INNER JOIN "baz" ON... WHERE ("foobar"."id" > 1) ... LIMIT 2 
2 

includes中添加意味着Rails将尝试将结果整合回一组不同的Foobar记录中。但是,这不会怎么find_each管理其批量工作:

Foobar.joins(:baz).includes(:baz).find_each(batch_size: 2) { |f| puts f.id } 
# SELECT "foobar"."id" AS t0_r0 ... LIMIT 2 
1 

而在这一点find_eachstop processing,因为它发现了一个早期的批次比批量大小小,因此它认为它是做:

# ActiveRecord::Batches#in_batches 
break if ids.length < batch_limit 

find_each的默认批量大小为1,000。您的问题案例返回了998条记录。这表明第一批它装载了998个小于批量大小的独特Foobar ID,find_each认为它已完成。它可能装载了1000个Baz记录,这些记录连接到998个不同的Foobar记录。

您可能需要查看您的baz表以确定它是否有任何重复条目。你可以像这样做:

Baz.group(:foobar_id).having('count(*) > 1') 

最好的解决办法是使用一个唯一索引,以避免在数据库中的重复和执行has_one关系。另一种方法是确保你得到一组类似的Foobar记录:

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 
相关问题