{"Entry":{"collection":"plan","key":"append","name":"Append","aliases":["Append","T_Append"],"metadata":{"aliases":["Append","T_Append"],"category":"Combination","content_hash":"7b84df68f27b010d9415995931cc4f4eeee175de068b68a7ee3bf105e4e15287","imported_at":"2026-09-30T00:40:44.039069+08:00","name":"Append","name_zh":"Append","slug":"append","summary":"Visits its child plans and combines their rows."}},"Definition":{"Collection":"plan","Key":"append","SourceDatabase":"center","Version":"18","SourceTable":"plan_node","SourceKey":"append","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"comparison_data":{"initializer":"ExecInitAppend","memory_mechanism":"unclassified","node_tag":"T_Append","parallel_callbacks":["ExecAppendEstimate","ExecAppendInitializeDSM","ExecAppendInitializeWorker","ExecAppendReInitializeDSM"],"partial_modes":[],"strategies":[],"text_names":["Append"]},"comparison_hash":"05fc087ef5a99b9d2d14f9b7e397d941085dafd8c263de24871ec9926b47ad8f","description":["Visits its child plans and combines their rows."],"evidence_kind":"source and documentation","explain_names":["Append"],"explain_prefixes":["Parallel","Async"],"facts":[{"label":"Core node tag","value":"T_Append"},{"label":"Structured EXPLAIN Node Type","value":"Append"},{"label":"Inputs","value":"Multiple child plans"},{"label":"Output","value":"Combined tuples"},{"label":"Executor initializer","value":"ExecInitAppend"},{"label":"Memory mechanism","value":"unclassified"}],"memory":{"description":"This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.","evidence":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeAppend.c","path":"src/backend/executor/nodeAppend.c","sha256":"bfe49b7e44ce4c31878392c3d84eb5c6fa97a5185a39aca44ff1914033a84ad3","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"mechanism":"unclassified","source_notes":[]},"node_tag":"T_Append","parallel_callbacks":["ExecAppendEstimate","ExecAppendInitializeDSM","ExecAppendInitializeWorker","ExecAppendReInitializeDSM"],"partial_modes":[],"related":[{"label":"EXPLAIN","url":"/wiki/sql/explain/?v=18"},{"label":"Using EXPLAIN","url":"/docs/18/using-explain.html"},{"label":"Parallel plans","url":"/docs/18/parallel-plans.html"},{"label":"enable_parallel_append","url":"/wiki/guc/enable_parallel_append/?v=18"},{"label":"enable_async_append","url":"/wiki/guc/enable_async_append/?v=18"}],"release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"runtime_verified":false,"sections":[{"paragraphs":["Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.","Text names recorded by this source: Append.","Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node."],"title":"EXPLAIN names and attributes"},{"paragraphs":["This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider."],"title":"Memory and temporary storage"},{"paragraphs":["The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.","Callbacks in this build: ExecAppendEstimate, ExecAppendInitializeDSM, ExecAppendInitializeWorker, ExecAppendReInitializeDSM."],"title":"Parallel execution and instrumentation"},{"paragraphs":["Normally, EXPLAIN will display every plan node created by the planner. However, there are cases where the executor can determine that certain nodes need not be executed because they cannot produce any rows, based on parameter values that were not available at planning time. (Currently this can only happen for child nodes of an Append or MergeAppend node that is scanning a partitioned table.) When this happens, those plan nodes are omitted from the EXPLAIN output and a Subplans Removed: N annotation appears instead.","Whenever PostgreSQL needs to combine rows from multiple sources into a single result set, it uses an Append or MergeAppend plan node. This commonly happens when implementing UNION ALL or when scanning a partitioned table. Such nodes can be used in parallel plans just as they can in any other plan. However, in a parallel plan, the planner may instead use a Parallel Append node.","When an Append node is used in a parallel plan, each process will execute the child plans in the order in which they appear, so that all participating processes cooperate to execute the first child plan until it is complete and then move to the second plan at around the same time. When a Parallel Append is used instead, the executor will instead spread out the participating processes as evenly as possible across its child plans, so that multiple child plans are executed simultaneously. This avoids contention, and also avoids paying the startup cost of a child plan in those processes that never execute it.","Also, unlike a regular Append node, which can only have partial children when used within a parallel plan, a Parallel Append node can have both partial and non-partial child plans. Non-partial children will be scanned by only a single process, since scanning them more than once would produce duplicate results. Plans that involve appending multiple result sets can therefore achieve coarse-grained parallelism even when efficient partial plans are not available. For example, consider a query against a partitioned table that can only be implemented efficiently by using an index that does not support parallel scans. The planner might choose a Parallel Append of regular Index Scan plans; each individual index scan would have to be executed to completion by a single process, but different scans could be performed at the same time by different processes."],"title":"Same-version manual discussion"},{"blocks":[{"code":"EXPLAIN UPDATE gtest_parent SET f1 = CURRENT_DATE WHERE f2 = 101;\n\n                                       QUERY PLAN\n----------------------------------------------------------------------------------------\n Update on gtest_parent  (cost=0.00..3.06 rows=0 width=0)\n   Update on gtest_child gtest_parent_1\n   Update on gtest_child2 gtest_parent_2\n   Update on gtest_child3 gtest_parent_3\n   -\u003e  Append  (cost=0.00..3.06 rows=3 width=14)\n         -\u003e  Seq Scan on gtest_child gtest_parent_1  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)\n         -\u003e  Seq Scan on gtest_child2 gtest_parent_2  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)\n         -\u003e  Seq Scan on gtest_child3 gtest_parent_3  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)","paragraphs":["Example copied from the PostgreSQL 18.6 manual; it was not executed for this collection.","When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:"],"source":{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}}],"title":"Examples from this manual build"},{"paragraphs":["NOTES Each append node contains a list of one or more subplans which must be iteratively processed (forwards or backwards). Tuples are retrieved by executing the 'whichplan'th subplan until the subplan stops returning tuples, at which point that plan is shut down and the next started up.","Append nodes don't make use of their left and right subtrees, rather they maintain a list of subplans so a typical append node looks like this in the plan tree:","... / Append -------+------+------+--- nil / \\ | | | nil nil ... ... ... subplans","Append nodes are currently used for unions, and to support inheritance queries, where several relations need to be scanned. For example, in our standard person/student/employee/student-emp example, where student and employee inherit from person and student-emp inherits from student and employee, the query:","| Append -------+-------+--------+--------+ / \\ | | | | nil nil Scan Scan Scan Scan | | | | person employee student student-emp"],"title":"Executor implementation notes"},{"code":"case T_Append:\n\t\t\tpname = sname = \"Append\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"source_inventory":{"executor":"src/backend/executor/execProcnode.c","explain":"src/backend/commands/explain.c","implementation":"src/backend/executor/nodeAppend.c"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1406","line":1406,"path":"src/backend/commands/explain.c","sha256":"34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/execProcnode.c:181","line":181,"path":"src/backend/executor/execProcnode.c","sha256":"f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeAppend.c","path":"src/backend/executor/nodeAppend.c","sha256":"bfe49b7e44ce4c31878392c3d84eb5c6fa97a5185a39aca44ff1914033a84ad3","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/include/nodes/plannodes.h","path":"src/include/nodes/plannodes.h","sha256":"52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS"},{"label":"PostgreSQL 18.6 · parallel-plans","path":"parallel-plans.html","sha256":"62207d207bead82b01b59dc119c4f95856f08655cc11d4699a05a40867ed2070","url":"/docs/18/parallel-plans.html#PARALLEL-APPEND"},{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}],"strategies":[],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"Append","label":"Append"}],"title":"EXPLAIN labels in this source build"}]},"ManualEvidence":{"release":{"channel":"stable","label":"18.6","major":"18","ref":"PostgreSQL 18.6 source archive","revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","source_snapshot_utc":"","source_url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1406","line":1406,"path":"src/backend/commands/explain.c","sha256":"34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/execProcnode.c:181","line":181,"path":"src/backend/executor/execProcnode.c","sha256":"f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeAppend.c","path":"src/backend/executor/nodeAppend.c","sha256":"bfe49b7e44ce4c31878392c3d84eb5c6fa97a5185a39aca44ff1914033a84ad3","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/include/nodes/plannodes.h","path":"src/include/nodes/plannodes.h","sha256":"52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS"},{"label":"PostgreSQL 18.6 · parallel-plans","path":"parallel-plans.html","sha256":"62207d207bead82b01b59dc119c4f95856f08655cc11d4699a05a40867ed2070","url":"/docs/18/parallel-plans.html#PARALLEL-APPEND"},{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}]},"MeasuredEvidence":{"runtime_verified":false}},"Text":{"Collection":"plan","Key":"append","SourceDatabase":"center","Version":"18","Locale":"en","Title":"Append","Summary":"Visits its child plans and combines their rows.","BodyHTML":"\u003cp\u003eVisits its child plans and combines their rows.\u003c/p\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"f719129f126b0c3568abdf4b3bda058935cb08641100a609f245d5c25b480f5d","Payload":{"description":["Visits its child plans and combines their rows."],"related":[{"label":"EXPLAIN","url":"/wiki/sql/explain/?v=18"},{"label":"Using EXPLAIN","url":"/docs/18/using-explain.html"},{"label":"Parallel plans","url":"/docs/18/parallel-plans.html"},{"label":"enable_parallel_append","url":"/wiki/guc/enable_parallel_append/?v=18"},{"label":"enable_async_append","url":"/wiki/guc/enable_async_append/?v=18"}],"sections":[{"paragraphs":["Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.","Text names recorded by this source: Append.","Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node."],"title":"EXPLAIN names and attributes"},{"paragraphs":["This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider."],"title":"Memory and temporary storage"},{"paragraphs":["The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.","Callbacks in this build: ExecAppendEstimate, ExecAppendInitializeDSM, ExecAppendInitializeWorker, ExecAppendReInitializeDSM."],"title":"Parallel execution and instrumentation"},{"paragraphs":["Normally, EXPLAIN will display every plan node created by the planner. However, there are cases where the executor can determine that certain nodes need not be executed because they cannot produce any rows, based on parameter values that were not available at planning time. (Currently this can only happen for child nodes of an Append or MergeAppend node that is scanning a partitioned table.) When this happens, those plan nodes are omitted from the EXPLAIN output and a Subplans Removed: N annotation appears instead.","Whenever PostgreSQL needs to combine rows from multiple sources into a single result set, it uses an Append or MergeAppend plan node. This commonly happens when implementing UNION ALL or when scanning a partitioned table. Such nodes can be used in parallel plans just as they can in any other plan. However, in a parallel plan, the planner may instead use a Parallel Append node.","When an Append node is used in a parallel plan, each process will execute the child plans in the order in which they appear, so that all participating processes cooperate to execute the first child plan until it is complete and then move to the second plan at around the same time. When a Parallel Append is used instead, the executor will instead spread out the participating processes as evenly as possible across its child plans, so that multiple child plans are executed simultaneously. This avoids contention, and also avoids paying the startup cost of a child plan in those processes that never execute it.","Also, unlike a regular Append node, which can only have partial children when used within a parallel plan, a Parallel Append node can have both partial and non-partial child plans. Non-partial children will be scanned by only a single process, since scanning them more than once would produce duplicate results. Plans that involve appending multiple result sets can therefore achieve coarse-grained parallelism even when efficient partial plans are not available. For example, consider a query against a partitioned table that can only be implemented efficiently by using an index that does not support parallel scans. The planner might choose a Parallel Append of regular Index Scan plans; each individual index scan would have to be executed to completion by a single process, but different scans could be performed at the same time by different processes."],"title":"Same-version manual discussion"},{"blocks":[{"code":"EXPLAIN UPDATE gtest_parent SET f1 = CURRENT_DATE WHERE f2 = 101;\n\n                                       QUERY PLAN\n----------------------------------------------------------------------------------------\n Update on gtest_parent  (cost=0.00..3.06 rows=0 width=0)\n   Update on gtest_child gtest_parent_1\n   Update on gtest_child2 gtest_parent_2\n   Update on gtest_child3 gtest_parent_3\n   -\u003e  Append  (cost=0.00..3.06 rows=3 width=14)\n         -\u003e  Seq Scan on gtest_child gtest_parent_1  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)\n         -\u003e  Seq Scan on gtest_child2 gtest_parent_2  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)\n         -\u003e  Seq Scan on gtest_child3 gtest_parent_3  (cost=0.00..1.01 rows=1 width=14)\n               Filter: (f2 = 101)","paragraphs":["Example copied from the PostgreSQL 18.6 manual; it was not executed for this collection.","When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:"],"source":{"label":"PostgreSQL 18.6 · using-explain","path":"using-explain.html","sha256":"60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed","url":"/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}}],"title":"Examples from this manual build"},{"paragraphs":["NOTES Each append node contains a list of one or more subplans which must be iteratively processed (forwards or backwards). Tuples are retrieved by executing the 'whichplan'th subplan until the subplan stops returning tuples, at which point that plan is shut down and the next started up.","Append nodes don't make use of their left and right subtrees, rather they maintain a list of subplans so a typical append node looks like this in the plan tree:","... / Append -------+------+------+--- nil / \\ | | | nil nil ... ... ... subplans","Append nodes are currently used for unions, and to support inheritance queries, where several relations need to be scanned. For example, in our standard person/student/employee/student-emp example, where student and employee inherit from person and student-emp inherits from student and employee, the query:","| Append -------+-------+--------+--------+ / \\ | | | | nil nil Scan Scan Scan Scan | | | | person employee student student-emp"],"title":"Executor implementation notes"},{"code":"case T_Append:\n\t\t\tpname = sname = \"Append\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"Append","label":"Append"}],"title":"EXPLAIN labels in this source build"}]}},"RequestedLocale":"zh-Hans","Fallback":true,"Versions":["10","11","12","13","14","15","16","17","18","19","20"],"Locales":["en"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
