Postgres和Ruby的续集:where子句中的空数组转换为慢速查询

时间:2015-11-30 05:19:58

标签: sql ruby postgresql sequel

我使用了优秀的续集ORM,并且在某些时候我生成了一系列ID,并且我试图检索具有这些ID的用户。 e.g。

user_ids = [1, 2, 3]
User.where(id: user_ids).all
# (0.004223s) SELECT * FROM "users" WHERE ("id" IN (1, 2, 3))

但有时,用户列表是空的,我实际得到的是:

User.where(id: []).all
# (0.421287s) SELECT * FROM "users" WHERE ("id" != "id")

结果是正确的(即没有返回行),但查询慢了两个数量级。

在包含数百万行的表中,可能需要几秒钟才能返回。

我很好奇为什么这个查询首先生成,但我也很好奇为什么Postgres查询规划器似乎没有检测到这个矛盾并立即返回一个空数据集。 / p>

对此有一个简洁的解决方案,还是我必须检查所有阵列是否空虚?

我使用Ruby 2.0.0,Sequel 4.24.0& Postgres 9.3.6。

2 个答案:

答案 0 :(得分:2)

有关此行为的closed issue on github

我同意jeremyevans没有必要修复,因为很明显,研究结果将永远是空的。此外,你会认为PostgreSQL应该足够聪明,可以优化这样的查询,不应该进行全表扫描。

因此,在代码中修复此行为以避免完全调用数据库更有意义恕我直言:

user_ids.present? ? User.where(id: user_ids) : []

答案 1 :(得分:1)

请注意,续集的默认行为在4.25.0中已更改,因此此类查询将使用false而不是id != id。虽然id != id在NULL处理方面可能更正确,但false的性能优势使其成为更好的默认值。