先看一个ModifyTable节点的例子:
postgres=# explain update test_01 set id = 5 where name = 'xxx'; QUERY PLAN --------------------------------------------------------------- Update on test_01 (cost=0.00..23.75 rows=6 width=48) -> Seq Scan on test_01 (cost=0.00..23.75 rows=6 width=48) Filter: ((name)::text = 'xxx'::text) (3 rows)你可能疑惑为啥上面的查询计划里面没有"ModifyTable"这样的字眼,下面是explain.c文件中的一段:
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; default: pname = "???"; break; } break;由此我们可以看到,对于ModifyTable节点,explain会判断是增删改中的哪一种从而作出判断。所以当在explain中看到INSERT、Update和Delete时,我们就知道这是走了ModifyTable节点。
那这里,我们还要再解释ModifyTable节点么?解释下吧:
* Apply rows produced by subplan(s) to result table(s), * by inserting, updating, or deleting.也就是说,我先从下层的subplan中获得rows,然后根据命令类型选择是insert, update还是delete操作。所以我们可以知道,这是一个顶层节点,它下面是查询节点(就是SELECT)。这也符合我们以前一直说的,所有的增删改查其实都是SELECT!
typedef struct ModifyTable { Plan plan; CmdType operation; /* INSERT, UPDATE, or DELETE */ bool canSetTag; /* do we set the command tag/es_processed? */ Index nominalRelation; /* Parent RT index for use of EXPLAIN */ List *resultRelations; /* integer list of RT indexes */ int resultRelIndex; /* index of first resultRel in plan's list */ List *plans; /* plan(s) producing source data */ List *withCheckOptionLists; /* per-target-table WCO lists */ List *returningLists; /* per-target-table RETURNING tlists */ List *fdwPrivLists; /* per-target-table FDW private data lists */ List *rowMarks; /* PlanRowMarks (non-locking only) */ int epqParam; /* ID of Param for EvalPlanQual re-eval */ OnConflictAction onConflictAction; /* ON CONFLICT action */ List *arbiterIndexes; /* List of ON CONFLICT arbiter index OIDs */ List *onConflictSet; /* SET for INSERT ON CONFLICT DO UPDATE */ Node *onConflictWhere; /* WHERE for ON CONFLICT UPDATE */ Index exclRelRTI; /* RTI of the EXCLUDED pseudo relation */ List *exclRelTlist; /* tlist of the EXCLUDED pseudo relation */ } ModifyTable;由于ModifyTable节点涉及的操作比较多,这里稍微解释下ModifyTable中的一些字段。
withCheckOptionLists字段这个和视图相关,我们知道创建视图有这样的用法:
CREATE VIEW xxx_view AS query WITH CHECK OPTION在postgres中,对创建语句中带有WITH CHECK OPTION的VIEW,在通过视图进行的操作(增删改),必须也能通过该视图看到操作后的结果。
也就是说:
对于INSERT,那么加的这条记录在视图查询后必须可以看到。
对于UPDATE,修改完的结果也必须能通过该视图看到。
对于DELETE,只能删除视图里有显示的记录。
因此对这一类操作,我们在操作表/视图的时候,要在(INSERT/UPDATE/DELETE的)WHERE条件中加上WITH OPTION中的条件。
returningLists字段这个很简单,因为postgres的语法中有类似以下的用法:
DELETE FROM xxx_table WHERE condition RETURNING xxx; UPDATE xxx_table SET a = '123' WHERE condition RETURNING xxx; INSERT INTO xxx_table VALUES (somevalues) RETURNING xxx;是的,postgres的RETURNING子句可以返回修改的行,所以对于含有RETURNING子句的查询,除了在对表中的数据进行INSERT/UPDATE/DELETE,还要额外返回一些行。即还要有额外的输出。
fdwPrivLists字段Postgres支持访问外部数据库的嘛,所以这个字段提供对fdw的处理的支持。
rowMarks字段这个和行锁相关,针对SELECT的LOCK子句:
FOR lock_strength [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ]具体见这里:
onConflictAction、arbiterIndexes、arbiterIndexes和onConflictWhere字段是的,对于INSERT操作,我们有以下语法(用于支持INSERT中发生的冲突):
INSERT INTO table_name VALUES (somevalues) ON CONFLICT [ conflict_target ] conflict_action 并且 conflict_action 是以下之一: DO NOTHING DO UPDATE SET { column_name = { expression | DEFAULT } | ( column_name [, ...] ) = ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...] ) = ( sub-SELECT ) } [, ...] [ WHERE condition ]这样一看,很容易对的上了。
exclRelRTI、exclRelTlist字段对于建表语句有以下子句:
EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ]EXCLUDE子句指定一个排除约束,它保证如果任意两行在指定列或表达式上使用指定操作符进行比较,不是所有的比较都将会返回TRUE。具体见: