ruby-on-rails – 您是否允许将find_each查询与includes语句一起
例:
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)(在实际查询中,第一个对象上有37个拆分30,第二个对象上有7个). 这是一个错误吗?是否包含find_each查询中不允许的内容?难道我做错了什么? Foobar和Baz之间的关系是Foobar has_one Baz和Baz属于Foobar. 解决方法
如果你的has_one关系不是真的has_one,就会发生这个问题.
假设您的数据库在列baz.foobar_id上没有唯一索引.然后你可能会意外地结束这样的情况,你有一个连接到多个Baz记录的Foobar记录: baz.id | baz.foobar_id ------ ------------- 1 1 2 1 3 2 在这种情况下,连接将返回Foobar和Baz记录的组合: Foobar.joins(:baz).count # This would be 3 这也意味着带有join的find_each会迭代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 添加包含意味着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_each将为stop processing,因为它发现早期批次小于批量大小,因此它认为已完成: # ActiveRecord::Batches#in_batches break if ids.length < batch_limit find_each的默认批处理大小为1,000.您的问题案例返回了998条记录.这表明第一批它加载了998个小于批量大小的独特Foobar ID,并且find_each认为它已经完成了.它可能装载了1,000条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 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |