{"Entry":{"collection":"plan","key":"gather","name":"Gather","aliases":["Gather","T_Gather"],"metadata":{"aliases":["Gather","T_Gather"],"category":"Parallelism","content_hash":"bc5c10ef300616be8410f15b621a14789ef9325912f54a4d163750740b3678c5","derived_content_hash":"bdf1631928a75a73f0560e0c03a595b9791b96a78813fad374807cab4b2edaae","imported_at":"2026-09-30T00:40:44.191527+08:00","name":"Gather","name_zh":"Gather","slug":"gather","summary":"Combines tuples from parallel workers and any participating leader execution."}},"Definition":{"Collection":"plan","Key":"gather","SourceDatabase":"center","Version":"18","SourceTable":"plan_node","SourceKey":"gather","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"comparison_data":{"initializer":"ExecInitGather","memory_mechanism":"unclassified","node_tag":"T_Gather","parallel_callbacks":[],"partial_modes":[],"strategies":[],"text_names":["Gather"]},"comparison_hash":"6fbd3ac9f7150ee72d4ae315dded3c145ee461d926c8ce6a04a1b8c6c31deee4","description":["Combines tuples from parallel workers and any participating leader execution."],"description_zh":"汇集并行工作进程以及参与执行的领导进程所产生的元组，不保证归并顺序。","description_zh_html":"\u003cp\u003e汇集并行工作进程以及参与执行的领导进程所产生的元组，不保证归并顺序。\u003c/p\u003e\u003cp\u003e核心节点标识：\u003ccode\u003eT_Gather\u003c/code\u003e；EXPLAIN 名称：\u003ccode\u003eGather\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e本版本源码中的并行执行或观测回调：该节点实现中未提取到此类回调。回调的存在不表示该节点必然支持共享并行扫描；在并行工作进程中执行也不等于具有并行感知能力。\u003c/p\u003e\u003ch3\u003e同版本中文手册节选\u003c/h3\u003e\u003cp\u003e\n\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 通过分两个阶段进行聚合来支持并行聚合。首先，每个参与查询并行部分的进程执行一个聚合步骤，为该进程所见到的每个分组产生一个部分结果。这在计划中体现为一个 \u003ccode class=\"literal\"\u003ePartial Aggregate\u003c/code\u003e 节点。然后，部分结果通过 \u003ccode class=\"literal\"\u003eGather\u003c/code\u003e 或 \u003ccode class=\"literal\"\u003eGather Merge\u003c/code\u003e 传送给领导者。最后，领导者会把来自所有工作进程的结果再次聚合，以产生最终结果。这在计划中体现为一个 \u003ccode class=\"literal\"\u003eFinalize Aggregate\u003c/code\u003e 节点。\n  \u003c/p\u003e\u003cp\u003e\n    由于 \u003ccode class=\"literal\"\u003eFinalize Aggregate\u003c/code\u003e 节点运行在领导者进程上，因此对于那些相对于输入行数会产生较多分组的查询，查询规划器会认为它不太有利。例如，在最坏情况下，\u003ccode class=\"literal\"\u003eFinalize Aggregate\u003c/code\u003e 节点看到的分组数可能与所有工作进程在 \u003ccode class=\"literal\"\u003ePartial Aggregate\u003c/code\u003e 阶段看到的输入行数一样多。对于这种情况，使用并行聚合显然不会带来性能收益。查询规划器会在规划过程中考虑这一点，因此在这种场景下不太可能选择并行聚合。\n  \u003c/p\u003e\u003cp\u003e\n    并行聚合并非在所有情况下都受支持。每个聚合都必须是\u003ca class=\"link\" href=\"/zh/docs/18/parallel-safety.html\"\u003e并行安全\u003c/a\u003e的，并且必须具有合并函数。如果该聚合具有类型为 \u003ccode class=\"literal\"\u003einternal\u003c/code\u003e 的转移状态，那么它还必须具有序列化和反序列化函数。更多细节请参见 \u003ca class=\"xref\" href=\"/zh/docs/18/sql-createaggregate.html\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE AGGREGATE\u003c/span\u003e\u003c/a\u003e。如果任何聚合函数调用包含 \u003ccode class=\"literal\"\u003eDISTINCT\u003c/code\u003e 或 \u003ccode class=\"literal\"\u003eORDER BY\u003c/code\u003e 子句，则不支持并行聚合。对于有序集聚合，或者当查询涉及 \u003ccode class=\"literal\"\u003eGROUPING SETS\u003c/code\u003e 时，也不支持并行聚合。只有当查询涉及的所有连接也都属于计划并行部分时，才能使用并行聚合。\n  \u003c/p\u003e\u003cp\u003e\u003ca href=\"/zh/docs/18/parallel-plans.html#PARALLEL-AGGREGATION\"\u003e查看完整中文手册与上下文\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e本页开头的中文说明为 PG.CENTER 对编辑说明的翻译；手册节选保留对应版本中文文档原文。源码信息及手册示例不代表重新进行过运行测试。\u003c/p\u003e","evidence_kind":"source and documentation","explain_names":["Gather"],"explain_prefixes":["Parallel","Async"],"facts":[{"label":"Core node tag","value":"T_Gather"},{"label":"Structured EXPLAIN Node Type","value":"Gather"},{"label":"Inputs","value":"One parallel child plan"},{"label":"Output","value":"Combined tuples without a merge-order guarantee"},{"label":"Executor initializer","value":"ExecInitGather"},{"label":"Memory mechanism","value":"unclassified"}],"facts_zh":[{"label":"核心节点标签","value":"T_Gather"},{"label":"结构化 EXPLAIN 节点类型","value":"Gather"},{"label":"输入","value":"一个并行子计划"},{"label":"输出","value":"合并后的元组，不保证归并顺序"},{"label":"执行器初始化函数","value":"ExecInitGather"},{"label":"内存机制","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/nodeGather.c","path":"src/backend/executor/nodeGather.c","sha256":"5dd854fbee33c36b3141f3297971f07aeea83a2a83c24cd99a03726fdf68bbb7","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"mechanism":"unclassified","source_notes":[]},"node_tag":"T_Gather","parallel_callbacks":[],"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":"max_parallel_workers_per_gather","url":"/wiki/guc/max_parallel_workers_per_gather/?v=18"},{"label":"parallel_leader_participation","url":"/wiki/guc/parallel_leader_participation/?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: Gather.","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: none extracted from this node implementation."],"title":"Parallel execution and instrumentation"},{"paragraphs":["PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node."],"title":"Same-version manual discussion"},{"paragraphs":["nodeGather.c Support routines for scanning a plan via multiple workers.","A Gather executor launches parallel workers to run multiple copies of a plan. It can also run the plan itself, if the workers are not available or have not started up yet. It then merges all of the results it produces and the results from the workers into a single output stream. Therefore, it will normally be used with a plan where running multiple copies of the same plan does not produce duplicate output, such as parallel-aware SeqScan.","Alternatively, a Gather node can be configured to use just one worker and the single-copy flag can be set. In this case, the Gather node will run the plan in one worker and will not execute the plan itself. In this case, it simply returns whatever tuples were returned by the worker. If a worker cannot be obtained, then it will run the plan itself and return the results. Therefore, a plan used with a single-copy Gather node need not be parallel-aware.","Leader may access ExecProcNode result directly (if need_to_scan_locally), or from workers via tuple queue. So we can't trivially rely on the slot type being fixed for expressions evaluated within this node.","Without projections result slot type is not trivially known, see comment above."],"title":"Executor implementation notes"},{"code":"case T_Gather:\n\t\t\tpname = sname = \"Gather\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"sections_zh":[{"paragraphs":["结构化格式使用上述 Node Type。文本格式名称还可能包含操作、策略、连接类型、扫描方向或聚合阶段属性。","此源码记录的文本名称：Gather.","并行感知与并行安全是不同的计划属性。在并行工作进程内运行的节点不一定是并行感知节点。"],"title":"EXPLAIN 名称与属性"},{"paragraphs":["本次抽取不为此节点设定统一的内存上限或落盘策略。请查看同一构建的实现、相关表达式或提供方。"],"title":"内存与临时存储"},{"paragraphs":["以下源码回调可以协调执行或收集工作进程的测量数据。回调存在不代表该节点普遍支持共享并行扫描或共享状态。","此构建的回调：none extracted from this node implementation."],"title":"并行执行与运行信息采集"},{"paragraphs":["PostgreSQL 通过分两个阶段进行聚合来支持并行聚合。首先，每个参与查询并行部分的进程执行一个聚合步骤，为该进程所见到的每个分组产生一个部分结果。这在计划中体现为一个 Partial Aggregate 节点。然后，部分结果通过 Gather 或 Gather Merge 传送给领导者。最后，领导者会把来自所有工作进程的结果再次聚合，以产生最终结果。这在计划中体现为一个 Finalize Aggregate 节点。"],"title":"同版本手册说明"},{"paragraphs":["nodeGather.c：通过多个工作进程扫描计划的支持例程。","Gather 执行器启动并行工作进程，运行一个计划的多个副本。如果工作进程不可用或尚未启动，它也可以自行运行此计划。然后，它将自身和工作进程产生的全部结果合并为单个输出流。因此，Gather 通常用于同时运行多个副本也不会产生重复输出的计划，例如可感知并行的 SeqScan。","另一种配置方式是让 Gather 节点只使用一个工作进程，并设置 single-copy 标志。此时，Gather 让一个工作进程运行计划，自身不执行计划，而是直接返回工作进程产生的元组。如果无法获得工作进程，Gather 会自行运行计划并返回结果。因此，单副本 Gather 节点使用的计划不必具备并行感知能力。","领导进程可能直接访问 ExecProcNode 的结果（need_to_scan_locally 为真时），也可能通过元组队列接收工作进程的结果。因此，不能简单假定在此节点内计算表达式时，元组槽类型始终固定。","没有投影时，结果槽位类型并非显而易见，参见上方注释。"],"title":"执行器实现说明"},{"code":"case T_Gather:\n\t\t\tpname = sname = \"Gather\";\n\t\t\tbreak;","title":"核心源码中的 EXPLAIN 标识"}],"source_inventory":{"executor":"src/backend/executor/execProcnode.c","explain":"src/backend/commands/explain.c","implementation":"src/backend/executor/nodeGather.c"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1438","line":1438,"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:355","line":355,"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/nodeGather.c","path":"src/backend/executor/nodeGather.c","sha256":"5dd854fbee33c36b3141f3297971f07aeea83a2a83c24cd99a03726fdf68bbb7","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 · parallel-plans","path":"parallel-plans.html","sha256":"62207d207bead82b01b59dc119c4f95856f08655cc11d4699a05a40867ed2070","url":"/docs/18/parallel-plans.html#PARALLEL-AGGREGATION"}],"strategies":[],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"Gather","label":"Gather"}],"title":"EXPLAIN labels in this source build"}],"tables_zh":[{"columns":[{"key":"label","label":"文本格式标签"},{"key":"identity","label":"结构化节点标识"}],"key":"explain-labels","rows":[{"identity":"Gather","label":"Gather"}],"title":"本构建中的 EXPLAIN 标签"}],"zh_from":{"authored_translation":"authored-translation-of-reviewed-guidance","body_sha256":"e3ed4468d93de0f95dab3ff35d21119cabad519e2213530c075037c3883428e3","kind":"same-version-chinese-manual-with-authored-translation-of-reviewed-guidance","manual":{"anchor":"PARALLEL-AGGREGATION","build_id":107,"extraction":"concept-introduction","fragment_sha256":"f882e19de96b3173fd88cb5de956b736c655192b92b7cdbf544225b9bedc6662","locale":"zh-Hans","page_key":"parallel-plans.html","source_hash":"1ef9f9a3740440f8dcdf04c2a2dfe2f7d48c66f2e0b102d15df580bff22a6857","source_revision":"unknown:rendered-translation-baseline","translated_from_revision":null,"translation_revision":"git:b1b500221dbe5437cfca004d6b04d3f6e422765d;html-sha256:08e987a66af27b98444a8057c256314eafa13611a3fb9e888214fc436824244b","url":"/zh/docs/18/parallel-plans.html#PARALLEL-AGGREGATION","version":"18"},"runtime_rerun":false,"source_facts_revision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}},"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:1438","line":1438,"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:355","line":355,"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/nodeGather.c","path":"src/backend/executor/nodeGather.c","sha256":"5dd854fbee33c36b3141f3297971f07aeea83a2a83c24cd99a03726fdf68bbb7","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 · parallel-plans","path":"parallel-plans.html","sha256":"62207d207bead82b01b59dc119c4f95856f08655cc11d4699a05a40867ed2070","url":"/docs/18/parallel-plans.html#PARALLEL-AGGREGATION"}]},"MeasuredEvidence":{"runtime_verified":false}},"Text":{"Collection":"plan","Key":"gather","SourceDatabase":"center","Version":"18","Locale":"en","Title":"Gather","Summary":"Combines tuples from parallel workers and any participating leader execution.","BodyHTML":"\u003cp\u003eCombines tuples from parallel workers and any participating leader execution.\u003c/p\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"87a5e9f2b860927ca3485fd8ccf5814d329e15c04f8ac7494cda26becca46fcc","Payload":{"description":["Combines tuples from parallel workers and any participating leader execution."],"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":"max_parallel_workers_per_gather","url":"/wiki/guc/max_parallel_workers_per_gather/?v=18"},{"label":"parallel_leader_participation","url":"/wiki/guc/parallel_leader_participation/?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: Gather.","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: none extracted from this node implementation."],"title":"Parallel execution and instrumentation"},{"paragraphs":["PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node."],"title":"Same-version manual discussion"},{"paragraphs":["nodeGather.c Support routines for scanning a plan via multiple workers.","A Gather executor launches parallel workers to run multiple copies of a plan. It can also run the plan itself, if the workers are not available or have not started up yet. It then merges all of the results it produces and the results from the workers into a single output stream. Therefore, it will normally be used with a plan where running multiple copies of the same plan does not produce duplicate output, such as parallel-aware SeqScan.","Alternatively, a Gather node can be configured to use just one worker and the single-copy flag can be set. In this case, the Gather node will run the plan in one worker and will not execute the plan itself. In this case, it simply returns whatever tuples were returned by the worker. If a worker cannot be obtained, then it will run the plan itself and return the results. Therefore, a plan used with a single-copy Gather node need not be parallel-aware.","Leader may access ExecProcNode result directly (if need_to_scan_locally), or from workers via tuple queue. So we can't trivially rely on the slot type being fixed for expressions evaluated within this node.","Without projections result slot type is not trivially known, see comment above."],"title":"Executor implementation notes"},{"code":"case T_Gather:\n\t\t\tpname = sname = \"Gather\";\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":"Gather","label":"Gather"}],"title":"EXPLAIN labels in this source build"}]}},"RequestedLocale":"en","Fallback":false,"Versions":["10","11","12","13","14","15","16","17","18","19","20"],"Locales":["en","zh-Hans"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
