IN 子句中可以使用的标量的最大数量是多少?

What is the maximum number of scalars that can be used in an IN clause?

每当我使用一个小语句例如:

DELETE FROM c_ordertax WHERE (c_order_id,c_tax_id) IN ((183691598,1000862),(183691198,1000862));

它执行得很好......但是如果我执行一个冗长的语句来删除具有这些标量值的 18755 条记录,它会说 "max_stack_depth" 超出了......postgresql.conf 中的这个选项已经设置到 2MB,而抛出错误的查询甚至还不到 2MB,只有 300kb

注意:table

中没有附加触发器

关于其他查询,我注意到的一件事是,当我在 IN 子句中使用单个值时,例如:DELETE FROM c_ordertax WHERE (c_order_id) IN ((183691598),(183691198)); 它们没有任何问题,无论查询可能有多长,它都能完美执行...

我目前的选择是:

  1. 我可以增加 "max_stack_depth" 值,但仅限于 8MB 并增加它会导致问题和 postgresql 服务器 无法重新启动...它只能正确重新启动该选项是 设置为小于 8MB 的值
  2. 我可以拆分这些语句,但它可能不优雅 解决方案,这也需要我知道最大标量值 可以容纳在单个语句中,如果字段数 标量值的增加,可以是值的总数 在单个语句中使用可以减少我担心...

所以我的问题是可以在 IN 子句中使用的标量值的最大数量是多少...如果标量值中的字段数量增加,是否有可用于确定最大值的公式可以使用的标量值的数量,例如:

5 values with 2 fields => ((1,2),(1,2),(1,2),(1,2),(1,2))
2 values with 3 fields => ((1,2,3),(1,2,3))

有数据库策划者遇到过这些问题吗?如果是这样,我该如何解决?

如果将标量值列表重写为 values() 列表,它应该可以工作:

DELETE FROM c_ordertax 
using (
  values 
      (183691598,1000862),
      (183691198,1000862)
) as t(ord_id,tax_id)
WHERE c_order_id = t.ord_id
  and c_tax_id = t.tax_id;

我在 values 列表中尝试了 10000 对,但没有抛出错误。然而,那是 Postgres 11。我现在没有可用的 9.3。

问题是 IN 对列表在解析阶段像这样转换:

EXPLAIN DELETE FROM large WHERE (id, id) IN ((1, 1), (2, 2), (3, 3), (4, 4), (5, 5));
                                                                      QUERY PLAN                                                                       
-------------------------------------------------------------------------------------------------------------------------------------------------------
 Delete on large  (cost=0.00..39425.00 rows=1 width=6)
   ->  Seq Scan on large  (cost=0.00..39425.00 rows=1 width=6)
         Filter: (((id = 1) AND (id = 1)) OR ((id = 2) AND (id = 2)) OR ((id = 3) AND (id = 3)) OR ((id = 4) AND (id = 4)) OR ((id = 5) AND (id = 5)))
(3 rows)

如果列表由标量组成,PostgreSQL 可以做得更好:

EXPLAIN DELETE FROM large WHERE id IN (1, 2, 3, 4, 5);
                          QUERY PLAN                           
---------------------------------------------------------------
 Delete on large  (cost=0.00..20675.00 rows=5 width=6)
   ->  Seq Scan on large  (cost=0.00..20675.00 rows=5 width=6)
         Filter: (id = ANY ('{1,2,3,4,5}'::integer[]))
(3 rows)

第二个版本将 运行 包含大列表,但第一个版本将 运行 在递归解析过程中达到限制。

我不确定这是否可以改进,但它可能不被视为值得花很多精力的案例。您随时可以像 "a_horse_with_no_name" 建议的那样重写您的查询。

通常,如果您有像这样的长 IN 列表,您可能做错了什么,例如尝试在数据库外执行连接。