{"Entry":{"collection":"plan","key":"windowagg","name":"WindowAgg","aliases":["T_WindowAgg","WindowAgg"],"metadata":{"aliases":["T_WindowAgg","WindowAgg"],"category":"Aggregation","content_hash":"bd6e222995ca4cf65b255ac5fc7ee1386aecc3c272498c3e91f45c9932b84868","derived_content_hash":"71a2ef1eab8e14b43241618430b1602c5ad7f6f2d23541d80b11cad478749e5e","imported_at":"2026-09-30T00:40:44.007359+08:00","name":"WindowAgg","name_zh":"WindowAgg","slug":"windowagg","summary":"Evaluates window functions over ordered partitions of its child output."}},"Definition":{"Collection":"plan","Key":"windowagg","SourceDatabase":"center","Version":"18","SourceTable":"plan_node","SourceKey":"windowagg","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","Facts":{"comparison_data":{"initializer":"ExecInitWindowAgg","memory_mechanism":"tuplestore","node_tag":"T_WindowAgg","parallel_callbacks":[],"partial_modes":[],"strategies":[],"text_names":["WindowAgg"]},"comparison_hash":"186aa5f13e96214f274161ba257307adf452233ebc64c9c0aaebfaee73fac8a4","description":["Evaluates window functions over ordered partitions of its child output."],"description_zh":"在子计划输出的有序分区上计算窗口函数。","description_zh_html":"\u003cp\u003e在子计划输出的有序分区上计算窗口函数。\u003c/p\u003e\u003cp\u003e核心节点标识：\u003ccode\u003eT_WindowAgg\u003c/code\u003e；EXPLAIN 名称：\u003ccode\u003eWindowAgg\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e本版本源码中的并行执行或观测回调：该节点实现中未提取到此类回调。回调的存在不表示该节点必然支持共享并行扫描；在并行工作进程中执行也不等于具有并行感知能力。\u003c/p\u003e\u003cp\u003e该节点使用受 \u003ccode\u003ework_mem\u003c/code\u003e 影响的元组存储，必要时可将存储的元组写入临时文件。这并不表示 \u003ccode\u003ework_mem\u003c/code\u003e 限制了该节点的所有内存分配。\u003c/p\u003e\u003ch3\u003e同版本中文手册节选\u003c/h3\u003e\u003cp\u003e\n\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e 会为收到的每个查询制定一个\u003cem class=\"firstterm\"\u003e查询计划\u003c/em\u003e。选择与查询结构和数据特性相匹配的正确计划，对获得良好的性能至关重要，因此系统内置了一个复杂的\u003cem class=\"firstterm\"\u003e规划器\u003c/em\u003e来尽量选出好的计划。可以使用 \u003ca class=\"link\" href=\"/zh/docs/18/sql-explain.html\"\u003e\u003ccode class=\"command\"\u003eEXPLAIN\u003c/code\u003e\u003c/a\u003e 命令查看规划器为任意查询生成的查询计划。读懂计划是一门需要经验积累的技能，本节将尝试介绍其中的基础知识。\n   \u003c/p\u003e\u003cp\u003e\n    本节中的示例取自执行过 \u003ccode class=\"command\"\u003eVACUUM ANALYZE\u003c/code\u003e 的回归测试数据库，使用的是 v18 开发版本源码。如果自行尝试这些示例，通常应当能得到相近的结果，但估计代价和行计数可能略有差异，因为 \u003ccode class=\"command\"\u003eANALYZE\u003c/code\u003e 生成的统计信息来自随机采样而非精确计数，而且代价本身在某种程度上也依赖于平台。\n   \u003c/p\u003e\u003cp\u003e\n    这些示例使用 \u003ccode class=\"command\"\u003eEXPLAIN\u003c/code\u003e 默认的\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003etext\u003c/span\u003e”\u003c/span\u003e输出格式，它紧凑且便于人工阅读。如果希望将 \u003ccode class=\"command\"\u003eEXPLAIN\u003c/code\u003e 的输出交给程序做进一步分析，则应改用机器可读的输出格式（XML、JSON 或 YAML）。\n   \u003c/p\u003e\u003cp\u003e\u003ca href=\"/zh/docs/18/using-explain.html\"\u003e查看完整中文手册与上下文\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e本页开头的中文说明为 PG.CENTER 对编辑说明的翻译；手册节选保留对应版本中文文档原文。源码信息及手册示例不代表重新进行过运行测试。\u003c/p\u003e","evidence_kind":"source and documentation","explain_names":["WindowAgg"],"explain_prefixes":["Parallel","Async"],"facts":[{"label":"Core node tag","value":"T_WindowAgg"},{"label":"Structured EXPLAIN Node Type","value":"WindowAgg"},{"label":"Inputs","value":"One suitably ordered child plan"},{"label":"Output","value":"Tuples with window-function results"},{"label":"Executor initializer","value":"ExecInitWindowAgg"},{"label":"Memory mechanism","value":"tuplestore"}],"facts_zh":[{"label":"核心节点标签","value":"T_WindowAgg"},{"label":"结构化 EXPLAIN 节点类型","value":"WindowAgg"},{"label":"输入","value":"一个满足排序要求的子计划"},{"label":"输出","value":"带窗口函数结果的元组"},{"label":"执行器初始化函数","value":"ExecInitWindowAgg"},{"label":"内存机制","value":"tuplestore"}],"memory":{"description":"This node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node.","evidence":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/executor/nodeWindowAgg.c","path":"src/backend/executor/nodeWindowAgg.c","sha256":"c365e6750bc77a89562254903d099c3e5914e001d3aae418322ccffc1d535d17","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"mechanism":"tuplestore","source_notes":["If the tuplestore has spilled to disk, alternate reading and writing becomes quite expensive due to frequent buffer flushes. It's cheaper to force the entire partition to get spooled in one go.","Read the current row from the tuplestore, and save in ScanTupleSlot. (We can't rely on the outerplan's output slot because we may have to read beyond the current row. Also, we have to actually copy the row out of the tuplestore, since window function evaluation might cause the tuplestore to dump its state to disk.)","Window functions do not have to call this, but are encouraged to move the mark forward when possible to keep the tuplestore size down and prevent having to spill rows to disk."]},"node_tag":"T_WindowAgg","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":"work_mem","url":"/wiki/guc/work_mem/?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: WindowAgg.","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 node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node.","If the tuplestore has spilled to disk, alternate reading and writing becomes quite expensive due to frequent buffer flushes. It's cheaper to force the entire partition to get spooled in one go.","Read the current row from the tuplestore, and save in ScanTupleSlot. (We can't rely on the outerplan's output slot because we may have to read beyond the current row. Also, we have to actually copy the row out of the tuplestore, since window function evaluation might cause the tuplestore to dump its state to disk.)","Window functions do not have to call this, but are encouraged to move the mark forward when possible to keep the tuplestore size down and prevent having to spill rows to disk."],"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":["A WindowAgg node evaluates \"window functions\" across suitable partitions of the input tuple set. Any one WindowAgg works for just a single window specification, though it can evaluate multiple window functions sharing identical window specifications. The input tuples are required to be delivered in sorted order, with the PARTITION BY columns (if any) as major sort keys and the ORDER BY columns (if any) as minor sort keys. (The planner generates a stack of WindowAggs with intervening Sort nodes as needed, if a query involves more than one window specification.)","Since window functions can require access to any or all of the rows in the current partition, we accumulate rows of the partition into a tuplestore. The window functions are called using the WindowObject API so that they can access those rows as needed.","We also support using plain aggregate functions as window functions. For these, the regular Agg-node environment is emulated for each partition. As required by the SQL spec, the output represents the value of the aggregate function over all rows in the current row's window frame.","All the window function APIs are called with this object, which is passed to window functions as fcinfo-\u003econtext.","We have one WindowStatePerFunc struct for each window function and window aggregate handled by this node."],"title":"Executor implementation notes"},{"code":"case T_WindowAgg:\n\t\t\tpname = sname = \"WindowAgg\";\n\t\t\tbreak;","title":"EXPLAIN identity in core source"}],"sections_zh":[{"paragraphs":["结构化格式使用上述 Node Type。文本格式名称还可能包含操作、策略、连接类型、扫描方向或聚合阶段属性。","此源码记录的文本名称：WindowAgg.","并行感知与并行安全是不同的计划属性。在并行工作进程内运行的节点不一定是并行感知节点。"],"title":"EXPLAIN 名称与属性"},{"paragraphs":["此节点使用 work_mem 创建 tuplestore。tuplestore 可以将存储的元组移到临时文件，但这不意味着 work_mem 限制了节点的全部内存分配。","tuplestore 已落盘时，交替读写会频繁刷新缓冲区，代价很高。一次性将整个分区存入临时存储会更便宜。","从 tuplestore 读取当前行并保存到 ScanTupleSlot。不能依赖外层计划的输出槽，因为可能需要读取当前行之后的数据。此外，必须将行实际复制出 tuplestore，因为窗口函数求值可能使 tuplestore 将其状态写入磁盘。","窗口函数并非必须调用此函数，但建议在可能时前移标记，以减小 tuplestore 大小并避免将行写入磁盘。"],"title":"内存与临时存储"},{"paragraphs":["以下源码回调可以协调执行或收集工作进程的测量数据。回调存在不代表该节点普遍支持共享并行扫描或共享状态。","此构建的回调：none extracted from this node implementation."],"title":"并行执行与运行信息采集"},{"paragraphs":["WindowAgg 节点在输入元组集合的适当分区上计算“窗口函数”。每个 WindowAgg 只处理一种窗口定义，但可以计算共享相同窗口定义的多个窗口函数。输入元组必须按排序顺序送达：PARTITION BY 列（如果有）为主要排序键，ORDER BY 列（如果有）为次要排序键。（如果查询包含多种窗口定义，规划器会按需生成多个堆叠的 WindowAgg，并在其间插入 Sort 节点。）","窗口函数可能需要访问当前分区的任意行乃至全部行，因此将分区行累积到元组存储。通过 WindowObject API 调用窗口函数，使其按需访问这些行。","也支持将普通聚合函数用作窗口函数。此时为每个分区模拟常规 Agg 节点环境。按 SQL 规范，输出为该聚合函数在当前行窗口框架内全部行上的结果。","所有窗口函数 API 都使用此对象调用；此对象通过 fcinfo-\u003econtext 传给窗口函数。","此节点处理的每个窗口函数和窗口聚合都对应一个 WindowStatePerFunc 结构。"],"title":"执行器实现说明"},{"code":"case T_WindowAgg:\n\t\t\tpname = sname = \"WindowAgg\";\n\t\t\tbreak;","title":"核心源码中的 EXPLAIN 标识"}],"source_inventory":{"executor":"src/backend/executor/execProcnode.c","explain":"src/backend/commands/explain.c","implementation":"src/backend/executor/nodeWindowAgg.c"},"sources":[{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/commands/explain.c:1574","line":1574,"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:345","line":345,"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/nodeWindowAgg.c","path":"src/backend/executor/nodeWindowAgg.c","sha256":"c365e6750bc77a89562254903d099c3e5914e001d3aae418322ccffc1d535d17","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"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}],"strategies":[],"tables":[{"columns":[{"key":"label","label":"Text-format label"},{"key":"identity","label":"Structured node identity"}],"key":"explain-labels","rows":[{"identity":"WindowAgg","label":"WindowAgg"}],"title":"EXPLAIN labels in this source build"}],"tables_zh":[{"columns":[{"key":"label","label":"文本格式标签"},{"key":"identity","label":"结构化节点标识"}],"key":"explain-labels","rows":[{"identity":"WindowAgg","label":"WindowAgg"}],"title":"本构建中的 EXPLAIN 标签"}],"zh_from":{"authored_translation":"authored-translation-of-reviewed-guidance","body_sha256":"adcc9f5870a965037f705cadd429a5fc3378dd588a9d57b851eee4dad83ed3ce","kind":"same-version-chinese-manual-with-authored-translation-of-reviewed-guidance","manual":{"anchor":"","build_id":107,"extraction":"concept-introduction","fragment_sha256":"15fbdf84b8f499253ade4f4a5841de138619a9933b93cc241d431dbe922fa40c","locale":"zh-Hans","page_key":"using-explain.html","source_hash":"d2f749744b3ac5aa2eb0154f295e8163903cd20fcc130c74c6172cdf2ae3a9df","source_revision":"unknown:rendered-translation-baseline","translated_from_revision":null,"translation_revision":"git:b1b500221dbe5437cfca004d6b04d3f6e422765d;html-sha256:08e987a66af27b98444a8057c256314eafa13611a3fb9e888214fc436824244b","url":"/zh/docs/18/using-explain.html","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:1574","line":1574,"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:345","line":345,"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/nodeWindowAgg.c","path":"src/backend/executor/nodeWindowAgg.c","sha256":"c365e6750bc77a89562254903d099c3e5914e001d3aae418322ccffc1d535d17","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"},{"archive_sha256":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","label":"src/backend/utils/sort/tuplestore.c","path":"src/backend/utils/sort/tuplestore.c","sha256":"27a85416bafed557006c705ab5d0c5dce3d3c1702812bb54d136f2ac4c41055a","url":"https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2"}]},"MeasuredEvidence":{"runtime_verified":false}},"Text":{"Collection":"plan","Key":"windowagg","SourceDatabase":"center","Version":"18","Locale":"en","Title":"WindowAgg","Summary":"Evaluates window functions over ordered partitions of its child output.","BodyHTML":"\u003cp\u003eEvaluates window functions over ordered partitions of its child output.\u003c/p\u003e","SourceRevision":"555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f","ContentHash":"7f269811b2c35d950ebe1bcaef26ecb177f2380828f53d414e16e66c21efa961","Payload":{"description":["Evaluates window functions over ordered partitions of its child output."],"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":"work_mem","url":"/wiki/guc/work_mem/?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: WindowAgg.","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 node creates a tuplestore with work_mem. The tuplestore can move stored tuples to temporary files; this does not make work_mem a cap on every allocation made by the node.","If the tuplestore has spilled to disk, alternate reading and writing becomes quite expensive due to frequent buffer flushes. It's cheaper to force the entire partition to get spooled in one go.","Read the current row from the tuplestore, and save in ScanTupleSlot. (We can't rely on the outerplan's output slot because we may have to read beyond the current row. Also, we have to actually copy the row out of the tuplestore, since window function evaluation might cause the tuplestore to dump its state to disk.)","Window functions do not have to call this, but are encouraged to move the mark forward when possible to keep the tuplestore size down and prevent having to spill rows to disk."],"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":["A WindowAgg node evaluates \"window functions\" across suitable partitions of the input tuple set. Any one WindowAgg works for just a single window specification, though it can evaluate multiple window functions sharing identical window specifications. The input tuples are required to be delivered in sorted order, with the PARTITION BY columns (if any) as major sort keys and the ORDER BY columns (if any) as minor sort keys. (The planner generates a stack of WindowAggs with intervening Sort nodes as needed, if a query involves more than one window specification.)","Since window functions can require access to any or all of the rows in the current partition, we accumulate rows of the partition into a tuplestore. The window functions are called using the WindowObject API so that they can access those rows as needed.","We also support using plain aggregate functions as window functions. For these, the regular Agg-node environment is emulated for each partition. As required by the SQL spec, the output represents the value of the aggregate function over all rows in the current row's window frame.","All the window function APIs are called with this object, which is passed to window functions as fcinfo-\u003econtext.","We have one WindowStatePerFunc struct for each window function and window aggregate handled by this node."],"title":"Executor implementation notes"},{"code":"case T_WindowAgg:\n\t\t\tpname = sname = \"WindowAgg\";\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":"WindowAgg","label":"WindowAgg"}],"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}
