我有两个postgres数据库(一个用于开发,一个用于测试)。
我在两个表上运行这个查询(将一个表合并到另一个表中)
WITH moved_rows AS
(
DELETE FROM mybigtable_20220322
RETURNING *
)
INSERT INTO mybigtable_202203
SELECT * FROM moved_rows;
但是我在每个版本上得到的EXPLAIN结果略有不同。
- 开发 *(Postgres 13.1)-
Insert on mybigtable_202203 (cost=363938.39..545791.17 rows=9092639 width=429)
CTE moved_rows
-> Delete on mybigtable_20220322 (cost=0.00..363938.39 rows=9092639 width=6)
-> Seq Scan on mybigtable_20220322 (cost=0.00..363938.39 rows=9092639 width=6)
-> CTE Scan on moved_rows (cost=0.00..181852.78 rows=9092639 width=429)
- 测试 *(Postgres 14.1)-
Insert on mybigtable_202203 (cost=372561.91..558377.73 rows=0 width=0)
CTE moved_rows
-> Delete on mybigtable_20220322 (cost=0.00..372561.91 rows=9290791 width=6)
-> Seq Scan on mybigtable_20220322 (cost=0.00..372561.91 rows=9290791 width=6)
-> CTE Scan on moved_rows (cost=0.00..185815.82 rows=9290791 width=429)
最大的区别是第一行,在开发中我得到rows=9092639 width=429
,在测试中我得到rows=0 width=0
所有表都具有相同的定义,具有相同的索引(并不是说它们似乎被使用),查询在两个数据库上都成功,EXPLAIN
指示两个数据库上的类似成本,并且每个数据库上的表具有类似的记录计数(刚刚超过900万行)。
在实践中,不同之处在于,在 * 开发 * 上,查询需要几分钟,在 * 测试 * 上需要几个小时。
这两个数据库都是用相同的脚本创建的,所以应该是100%相同的,我的猜测是有一些小的,微妙的差异,这是悄悄地在某处。任何建议的差异可能是什么或如何找到它?谢谢
更新
- 正在合并的两个表(在两个数据库上)已经在类似的时间范围内进行了真空分析。
- 我使用
fc
比较了两个数据库。有一个区别,在开发数据库上,表在其中一个索引上进行了聚类。我在测试表上进行了类似的聚类,但结果没有改变。 - 在回应评论“计划 * 是 * 相同的,只有估计的行数不同”。这个差异是我目前唯一的线索,一个潜在的问题。我的 * 开发 * 数据库是在一个10岁的服务器上挣扎缺乏资源,我的 test 数据库是一个全新的服务器。前者需要几分钟来实际运行查询,后者需要几个小时。每当我在论坛上发布问题时,我总是被告知“从解释计划开始”
2条答案
按热度按时间mctunoxg1#
此更改是在commit f0f13a3a08b27中进行的,它没有进入发行说明,因为它被认为是一个错误修复:
修复不带RETURNING的ModifyTable路径的估计值。
在过去,我们总是估计ModifyTable节点将发出与其子路径相同数量的行。如果没有RETURNING子句,正确的估计值为零。修复,为建议的对该数量敏感的并行写入补丁做准备。
剩下的问题是,对于RETURNING查询,估计的宽度基于子路径输出而不是RETURNING tlist。
审核人:Greg Nancarrowgregn4422@gmail.com
讨论:https://postgr.es/m/CAJcOf-cXnB5cnMKqWEp2E2z7Mvcd04iLVmV%3DqpFJrR3AcrTS3g%40mail.gmail.com
此更改仅影响
EXPLAIN
输出,而不影响数据修改期间实际发生的情况。6ljaweal2#
来解决这两种情况下不同的查询时间。
在处理像您这样的查询(批量删除和移动)时,考虑以下事项是有用的
最好在开始查询之前删除所有这些东西。在我的例子中,我在引用所述表的表中有外键(响应类型的列)。删除后,查询从〉4小时到〈30秒。