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

Postgres and Ruby's Sequel: Empty array in where-clause getting converted to slow query

我正在使用优秀的 Sequel ORM,在某些时候我已经生成了一个 ID 数组,我正在尝试检索具有这些 ID 的用户。例如

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")

结果正确(即没有行 returned),但查询速度慢了两个数量级。

在具有数百万行的表上,可能需要几秒钟才能 return。

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

是否有一个巧妙的解决方案,或者我是否必须检查所有数组是否为空?

我正在使用 Ruby 2.0.0、Sequel 4.24.0 和 Postgres 9.3.6。

关于此行为有一个 closed issue on github

我同意 jeremyevans 的观点,即不需要修复,因为很明显结果将而且应该始终为空。此外,您会认为 PostgreSQL 应该足够聪明来优化这样的查询,而不应该进行整个 table 扫描。

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

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

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