重写大型 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_id
在 SELECT
列表中看起来很可疑。可能是一个简化的示例查询。
【讨论】:
加入 values 子句而不是IN
是另一种有时更快的选项。参见例如here
是的,VALUES
表达式是子查询的一种形式,这对于大集合通常更快。主题的变体:在子查询中传递一个数组和unnest
。上面链接答案中的每个信息和更多链接。以上是关于重写大型 IN 子句的最高效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 中使用设置的 FPS 绘制大量简单、填充颜色的矩形的最高效方法是啥?