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

时间:2019-04-05 10:10:41

标签: sql database postgresql postgresql-9.3 scalar-subquery

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

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

注意:表中未附加任何触发器

关于其他查询,我注意到的一件事是,当我在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))

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

2 个答案:

答案 0 :(得分:2)

如果将标量值列表重写为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版本。

答案 1 :(得分:1)

问题是xxx.xx.x.xx - - [05/Apr/2019 10:00:15] "POST /diff HTTP/1.1" 400 - 对列表在解析阶段会像这样转换:

IN

如果列表包含标量,则PostgreSQL可以做得更好:

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)

第二个版本将使用较大的列表运行,但第一个版本将在递归解析过程中遇到限制。

我不确定是否可以改进,但是可能不值得花很多精力在案例上。您始终可以像建议的“ a_horse_with_no_name”一样重写查询。

通常,如果您有很长的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) 这样的列表,则您可能做错了某些事情,例如尝试在数据库外部执行联接。