1

我有一个场景,我在查询链中的某处有 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 连接将产生两个 INNER JOINS,而在我的情况下我只需要一个。

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

回复评论:

has_and_belongs_to_manyRails 产生两个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

如我错了请纠正我。

4

1 回答 1

1

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

这篇文章让我闻到了气味,作者展示了和我一模一样的问题,并且给 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

我不是一个常规的基准测试者,所以我的基准测试可能并不完美,但在我看来,我的更有效的方法确实对大型查询或大量查询进行了现实世界的性能改进。

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

于 2013-04-03T08:56:54.703 回答