ModifyTable
ModifyTable
执行计划指定的数据修改操作,并在请求时产生 RETURNING 行。
当前查看 PostgreSQL 18.6。
说明
执行计划指定的数据修改操作,并在请求时产生 RETURNING 行。
- 核心节点标签
- T_ModifyTable
- 结构化 EXPLAIN 节点类型
- ModifyTable
- 输入
- 一个或多个数据修改输入计划
- 输出
- 请求时输出 RETURNING 元组
- 执行器初始化函数
- ExecInitModifyTable
- 内存机制
- unclassified
EXPLAIN 名称与属性
结构化格式使用上述 Node Type。文本格式名称还可能包含操作、策略、连接类型、扫描方向或聚合阶段属性。
此源码记录的文本名称:Insert, Update, Delete, Merge.
并行感知与并行安全是不同的计划属性。在并行工作进程内运行的节点不一定是并行感知节点。
内存与临时存储
本次抽取不为此节点设定统一的内存上限或落盘策略。请查看同一构建的实现、相关表达式或提供方。
如果 FDW 支持批处理且请求了批处理,则累积行并分批插入,否则逐行插入。
初始化批次槽。由于不知道需要多少槽,随着批次增长逐步初始化,并在不同批次间保留。为缓解资源所有者处理大量引用对象时的低效情况,例如许多槽引用同一元组描述符,为每个槽复制相应的元组描述符。
并行执行与运行信息采集
以下源码回调可以协调执行或收集工作进程的测量数据。回调存在不代表该节点普遍支持共享并行扫描或共享状态。
此构建的回调:none extracted from this node implementation.
同版本手册说明
归并连接要求输入数据按连接键排序。在这个例子中,两个输入都通过索引扫描按正确顺序访问行而完成排序;不过也可以采用顺序扫描再排序的方式。(对于需要排序很多行的情况,顺序扫描加排序往往会胜过索引扫描,因为索引扫描需要非顺序磁盘访问。)
观察备选计划的一种方法,是利用 第 19.7.1 节 中描述的启用/禁用标志,强迫规划器忽略它认为最便宜的策略。(这是个粗糙但有用的工具。另见 第 14.3 节 。)例如,如果我们并不确信前一个示例中归并连接真的是最佳连接类型,可以试试:
这表明,规划器认为在这个场景下,哈希连接的代价几乎比归并连接高出 50%。当然,接下来的问题就是它是否判断正确。我们可以像 下文 所述,使用 EXPLAIN ANALYZE 来研究。
如本例所示,查询为 INSERT、UPDATE、DELETE 或 MERGE 命令时,实际应用表变更的工作由顶层 Insert、Update、Delete 或 Merge 计划节点完成。其下的计划节点负责定位旧行和/或计算新数据。因此,上例仍采用前面见过的位图表扫描,其输出传给 Update 节点,由后者存储更新后的行。虽然数据修改节点可能消耗相当多的运行时间(本例中占了绝大部分),但规划器目前并未将这部分工作计入代价估算。这是因为任何正确查询计划需要完成的这部分工作都相同,因此不会影响规划决策。
当 UPDATE 、 DELETE 或 MERGE 命令影响分区表或继承层次时,输出可能像这样:
在这个示例中,Update 节点需要考虑三个子表,而不包括最初提到的那个分区表,因为它本身并不存储任何数据。因此这里有三个输入扫描子计划,每个表对应一个。为了便于理解,Update 节点带有注释,显示将要更新的具体目标表,其顺序与对应子计划的顺序一致。
本版手册中的示例
示例摘自 PostgreSQL 18.6 手册;本百科未实际执行此示例。
另一种可能的连接方式是归并连接,如下所示:
EXPLAIN SELECT *
FROM tenk1 t1, onek t2
WHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;
QUERY PLAN
------------------------------------------------------------------------------------------
Merge Join (cost=0.56..233.49 rows=10 width=488)
Merge Cond: (t1.unique2 = t2.unique2)
-> Index Scan using tenk1_unique2 on tenk1 t1 (cost=0.29..643.28 rows=100 width=244)
Filter: (unique1 < 100)
-> Index Scan using onek_unique2 on onek t2 (cost=0.28..166.28 rows=1000 width=244)示例摘自 PostgreSQL 18.6 手册;本百科未实际执行此示例。
请记住,EXPLAIN ANALYZE 会实际执行查询,因此所有副作用都会照常发生,只是查询本应输出的结果被丢弃,改为打印 EXPLAIN 数据。如果希望分析修改数据的查询而不改变表,可以随后回滚命令,例如:
BEGIN;
EXPLAIN ANALYZE UPDATE tenk1 SET hundred = hundred + 1 WHERE unique1 < 100;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Update on tenk1 (cost=5.06..225.23 rows=0 width=0) (actual time=1.634..1.635 rows=0.00 loops=1)
-> Bitmap Heap Scan on tenk1 (cost=5.06..225.23 rows=100 width=10) (actual time=0.065..0.141 rows=100.00 loops=1)
Recheck Cond: (unique1 < 100)
Heap Blocks: exact=90
Buffers: shared hit=4 read=2
-> Bitmap Index Scan on tenk1_unique1 (cost=0.00..5.04 rows=100 width=0) (actual time=0.031..0.031 rows=100.00 loops=1)
Index Cond: (unique1 < 100)
Index Searches: 1
Buffers: shared read=2
Planning Time: 0.151 ms
Execution Time: 1.856 ms
ROLLBACK;执行器实现说明
说明:ModifyTable 从 outerPlan 接收输入:INSERT 时为待插入数据;UPDATE 和 MERGE 时为修改列的新值及行定位信息;DELETE 时仅为行定位信息。
待修改关系可以是普通表、外部表或视图。如果是视图,要么具有足够的 INSTEAD OF 触发器,要么此节点只执行 MERGE ... DO NOTHING。若原始 MERGE 指向不属于这两类的视图,之前的处理已把 ModifyTable 的结果关系改为该视图的底层关系。此节点会处理 ri_WithCheckOptions,其中可能包含那些可自动更新视图的表达式。
MERGE 对源关系和目标表执行连接。若包含 WHEN NOT MATCHED [BY TARGET] 子句,则使用可能输出没有匹配目标元组的外连接。此时,未匹配目标元组的行定位信息为 NULL,只能执行 INSERT。对于匹配的目标元组,使用行定位信息确定要 UPDATE 或 DELETE 的元组。若所有子句均为 WHEN MATCHED 或 WHEN NOT MATCHED BY SOURCE,连接输出的所有元组都包含匹配的目标元组,因此都有行定位信息。
如果查询指定了 RETURNING,ModifyTable 每完成一行的插入、更新或删除后就返回一个 RETURNING 元组,需要再次调用才能继续执行。如果没有 RETURNING,则在节点内部循环,直到全部工作完成,再返回 NULL,从而避免无用的调用/返回开销。
ModifyTable 操作的上下文结构体,包含基本执行状态,以及由 ExecUpdateAct() 和 ExecDeleteAct() 填充、用于向调用者报告执行结果的若干输出变量。
核心源码中的 EXPLAIN 标识
case T_ModifyTable:
sname = "ModifyTable";
switch (((ModifyTable *) plan)->operation)
{
case CMD_INSERT:
pname = operation = "Insert";
break;
case CMD_UPDATE:
pname = operation = "Update";
break;
case CMD_DELETE:
pname = operation = "Delete";
break;
case CMD_MERGE:
pname = operation = "Merge";
break;
default:
pname = "???";
break;
}
break;本构建中的 EXPLAIN 标签
| 文本格式标签 | 结构化节点标识 |
|---|---|
| Insert | ModifyTable |
| Update | ModifyTable |
| Delete | ModifyTable |
| Merge | ModifyTable |
相关条目
文档与源码
- src/backend/commands/explain.c:1385
- src/backend/executor/execProcnode.c:176
- src/backend/executor/nodeModifyTable.c
- src/include/nodes/plannodes.h
- PostgreSQL 18.6 · using-explain
- PostgreSQL 18.6 · using-explain
来源构建
- 版本
- 18.6
- 构建
- PostgreSQL 18.6 source archive
- 来源指纹
555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f
版本比较
PostgreSQL 17 → 18: 无变化。
比较已记录的接口与属性,排除来源指纹和构建元数据。某个样本中没有记录,不能据此判断实际引入或移除的版本。
导出 JSON · 返回执行计划节点 · 收录范围为 PostgreSQL 10 至 20;最早采样版本不一定是实际引入版本。