重写大型 IN 子句的最高效方法是啥?

Posted

技术标签:

【中文标题】重写大型 IN 子句的最高效方法是啥?【英文标题】:What is the most performant way to rewrite a large IN clause?重写大型 IN 子句的最高效方法是什么? 【发布时间】:2018-10-09 01:12:36 【问题描述】:

我使用 go 和 gorm 编写了一个 API,它在我们的数据库上运行计算并返回结果。

在使用聚合时,我刚刚达到了 IN 条件的参数限制。示例查询:

SELECT SUM(total_amount) from Table where user_id in(...70k parameters) group by user_id

我当前的一个边缘案例有 > 65535 个用户 ID,因此我的 Postgres 客户端抛出错误:

got 66037 parameters but PostgreSQL only supports 65535 parameters

我不确定解决此问题的最佳方法是什么。一个可以处理这种边缘情况的大量参数,同时不会影响我的典型用例。我是否将 id 分块并遍历将其存储在内存中的多个查询,直到获得所需的所有数据?使用ANY(VALUES)...

显然,从查询中我对 Postgres 的了解非常有限,因此非常感谢任何帮助。

【问题讨论】:

您使用所需的 user_id 创建一个表并进行左连接 【参考方案1】:

您可以将user_id IN (value [, ...]) 替换为以下之一:

user_id IN (subquery)
user_id = ANY (subquery)
user_id = ANY (array expression)

子查询和数组都没有表现出相同的限制。最短的输入语法是:

user_id = ANY ('1,2,3'::int[])  -- make array type match type of user_id

详细信息和更多选项:

How to use ANY instead of IN in a WHERE clause with Rails?

或者您可以创建一个(临时)表tmp_usr(user_id int),导入到它,可能使用SQL COPY 或psql \copy 而不是INSERT 以获得最佳性能非常大的集合,然后加入到表中,例如:

SELECT SUM(total_amount)
FROM   tbl
JOIN   tmp_usr USING (user_id)
GROUP  BY user_id;

顺便说一句,GROUP BY user_id 不包括 user_idSELECT 列表中看起来很可疑。可能是一个简化的示例查询。

【讨论】:

加入 values 子句而不是 IN 是另一种有时更快的选项。参见例如here 是的,VALUES 表达式是子查询的一种形式,这对于大集合通常更快。主题的变体:在子查询中传递一个数组和unnest。上面链接答案中的每个信息和更多链接。

以上是关于重写大型 IN 子句的最高效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

更新大型表上的行的最高效方法

在 Flutter 中使用设置的 FPS 绘制大量简单、填充颜色的矩形的最高效方法是啥?

为现有 C/C++ 库创建原型级 Python 绑定的最简单、最高效的方法是啥?

提高 CSS 特异性的最高效的方式是啥?

React-Native 中动态样式的最高效方式是啥?

在 BigQuery 中按 LOWER 高效排序