0

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

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

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

4

2 回答 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;

我在列表中尝试了 10000 对,values但没有引发错误。然而,那是 Postgres 11。我现在没有 9.3。

于 2019-04-05T10:34:15.867 回答
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列表,你可能做错了什么,比如试图在数据库之外执行连接。

于 2019-04-05T11:02:32.907 回答