PostgreSQL – “IN”子句中的最大参数数量?

在Postgres中,你可以指定一个IN子句,如下所示:

SELECT * FROM user WHERE id IN (1000, 1001, 1002) 

有谁知道你可以传入IN的最大参数数量是多less?

根据位于这里的源代码,从第850行开始, PostgreSQL没有明确限制参数的数量。

以下是来自第870行的代码注释:

 /* * We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only * possible if the inputs are all scalars (no RowExprs) and there is a * suitable array type available. If not, we fall back to a boolean * condition tree with multiple copies of the lefthand expression. * Also, any IN-list items that contain Vars are handled as separate * boolean conditions, because that gives the planner more scope for * optimization on such clauses. * * First step: transform all the inputs, and detect whether any are * RowExprs or contain Vars. */ 
 explain select * from test where id in (values (1), (2)); 

QUERY PLAN

  Seq Scan on test (cost=0.00..1.38 rows=2 width=208) Filter: (id = ANY ('{1,2}'::bigint[])) 

但如果尝试第二个查询:

 explain select * from test where id = any (values (1), (2)); 

QUERY PLAN

 Hash Semi Join (cost=0.05..1.45 rows=2 width=208) Hash Cond: (test.id = "*VALUES*".column1) -> Seq Scan on test (cost=0.00..1.30 rows=30 width=208) -> Hash (cost=0.03..0.03 rows=2 width=4) -> Values Scan on "*VALUES*" (cost=0.00..0.03 rows=2 width=4) 

我们可以看到postgres生成临时表并join它

传递给IN子句的元素数量没有限制。 如果有更多的元素,它会认为它是数组,然后对数据库中的每个扫描,它将检查它是否包含在数组中。 这种方法不具有可扩展性。 而不是使用IN子句尝试使用INNER JOIN与临时表。 请参阅http://www.xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic/了解更多信息。; 使用INNER JOIN可以很好地扩展,因为查询优化器可以利用散列连接和其他优化。 而在IN子句中,优化器没有办法优化查询。 我注意到这个变化至less有2倍的加速。

这不是对现在问题的真正答案,但也可以帮助其他人。

至less我可以告诉,使用Posgresql的JDBC驱动程序9.1可以通过PostgreSQL后端传递32767个值(= Short.MAX_VALUE)的技术限制。

这是使用postgresql jdbc驱动程序“从x where ID in(… 100k values …)中删除”的一个testing:

 Caused by: java.io.IOException: Tried to send an out-of-range integer as a 2-byte value: 100000 at org.postgresql.core.PGStream.SendInteger2(PGStream.java:201) 

您可能需要考虑重构该查询,而不是添加任意长的ID列表…如果ID确实遵循示例中的模式,则可以使用范围:

 SELECT * FROM user WHERE id >= minValue AND id <= maxValue; 

另一个select是添加一个内部select:

 SELECT * FROM user WHERE id IN ( SELECT userId FROM ForumThreads ft WHERE ft.id = X ); 

如果您有如下查询:

 SELECT * FROM user WHERE id IN (1, 2, 3, 4 -- and thousands of another keys) 

你可以提高性能,如果重写你的查询,如:

 SELECT * FROM user WHERE id = ANY(VALUES (1), (2), (3), (4) -- and thousands of another keys)