避免Rails ActiveRecord查询中的重复连接

时间:2013-04-02 16:33:29

标签: ruby-on-rails

我有一个场景,我在查询链中的某处有SQL连接,然后在某些情况下,我需要附加一个需要相同连接的条件,但我不知道此时是否已存在该连接在范围内。例如:

@foo = Foo.joins("INNER JOIN foos_bars ON foos_bars.foo_id = foos.id")
....
@foo.joins(:bars).where(bars: { id: 1 })

这将产生有关重复的表/别名的SQL错误。

我在第一个实例中手动编写SQL连接的原因是为了提高效率,因为经典的rails AREL join将生成两个INNER JOINS,在我的情况下我只需要一个。

有没有推荐的解决方法?例如,检查当前在范围内的连接的某种方法。

对评论的回应:

使用has_and_belongs_to_many关系,Rails会生成两个INNER JOINS,如下所示:

SELECT "journals".* FROM "journals"
INNER JOIN "categories_journals"
  ON "categories_journals"."journal_id" = "journals"."id"
INNER JOIN "categories"
  ON "categories"."id" = "categories_journals"."category_id"
WHERE "categories"."id" = 1

而我相信我可以这样做:

SELECT "journals".* FROM "journals"
INNER JOIN "categories_journals"
  ON "categories_journals"."journal_id" = "journals"."id"
WHERE "categories_journals"."category_id" = 1

如果我错了,请纠正我。

1 个答案:

答案 0 :(得分:1)

解决方案是普遍使用字符串连接。我不知道Rails实际上是uniq的字符串连接 - 所以只要它们字符串相同就不会发生这个问题。

This article 让我闻到了气味,作者展示了与我完全相同的问题并修补了Rails,看起来这个补丁很久以前就已经实现了。我不认为它是完美的。 rails应该有一种方法来处理哈希参数连接和字符串连接,而不是在它们重叠时弹出。可能看看我是否可以补丁..

编辑:

我做了几个基准测试,看看我是否真的在担心什么都没有(在两种加入方式之间):

1.9.3p194 :008 > time = Benchmark.realtime { 1000.times { a = Incident.joins("INNER JOIN categories_incidents ON categories_incidents.incident_id = incidents.id").where("categories_incidents.category_id = 1") } }
 => 0.042458 
1.9.3p194 :009 > time = Benchmark.realtime { 1000.times { a = Incident.joins(:categories).where(categories: { id: 1 }) } }
 => 0.152703

我不是常规的基准测试程序,因此我的基准测试可能并不完美,但在我看来,好像我的更有效的方法可以在大型查询或大量查询中实现真正的性能提升。

加入我所做的方式的缺点是,如果Category不存在但仍然记录在连接表中,那么这可能会导致一些问题,否则可以通过更彻底的问题来避免加入。