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

问题描述 投票:0回答:2

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

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))

任何数据库Mastermind都遇到过这些问题?如果是这样我该如何解决?

sql database postgresql postgresql-9.3 scalar-subquery
2个回答
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
投票

问题是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列表,你可能做错了,比如尝试在数据库外执行连接。

© www.soinside.com 2019 - 2024. All rights reserved.