窗口函数内存占用高主因是分区排序数据超限落盘或缓冲区配置不当:PostgreSQL需调大work_mem并局部设置,Spark需同步调整buffer.in.memory.threshold和spill.threshold,且PARTITION BY字段须选高基数列以均衡分区。

窗口函数内存占用高,通常不是SQL写错了,而是执行引擎在分区排序时把太多数据塞进内存——关键得看它用什么结构缓存、按什么字段分区、以及有没有被其他任务挤占资源。
PostgreSQL:work_mem调得太小,窗口排序直接落盘
PostgreSQL窗口函数(如ROW_NUMBER()、SUM() OVER ())对每个PARTITION BY组独立做排序,全靠work_mem撑着。一旦单个分区排序数据量超限,就会走external merge Disk,IO暴涨、耗时翻倍。
- 先确认是否落盘:运行
EXPLAIN (ANALYZE, BUFFERS),看Sort或WindowAgg节点有没有Sort Method: external merge Disk - 别全局改
postgresql.conf——报表类查询才需要大work_mem,OLTP会崩 - 安全做法是在应用里执行前加:
BEGIN; SET LOCAL work_mem = '64MB'; SELECT ...; COMMIT; - 注意并发:一个查询含3个窗口函数,可能同时启3个排序,峰值内存 ≈ 3 ×
work_mem
Spark:ExternalAppendOnlyUnsafeRowArray吃光堆内存
Spark默认用ExternalAppendOnlyUnsafeRowArray缓存每个窗口的数据,只要单个分区行数超过spark.sql.windowExec.buffer.in.memory.threshold(默认4096),就触发落盘;但高并发下大量缓冲区并行驻留,GC跟不上,OOM就来了。
- 必须同时调两个参数:
spark.sql.windowExec.buffer.in.memory.threshold(建议8192)和spark.sql.windowExec.buffer.spill.threshold(建议30000),只调一个等于白干 - 提交作业时加:
spark-submit --conf spark.sql.windowExec.buffer.in.memory.threshold=8192 --conf spark.sql.windowExec.buffer.spill.threshold=30000 -
spill.threshold设太低(如5000)→ 频繁写磁盘;设太高(如Integer.MAX_VALUE)→ UnsafeExternalSorter在内存攒太多数据,OOM风险不降
PARTITION BY字段选错,压力全压在一个桶里
这个点最隐蔽:日志不报错、EXPLAIN看不出异常,但内存就是爆。比如按status(只有'active'/'inactive'/'pending'三个值)分区,90%数据挤进active这一个分区,窗口数据量爆炸;换成user_id或order_id这类高基数字段,压力才真正摊开。
- 检查方式:用
EXPLAIN (VERBOSE)或EXPLAIN (FORMAT JSON)看实际生成的partition数量分布 - 如果
PARTITION BY字段基数极低( - 配合
ROWS BETWEEN限制窗口大小,比如ROWS BETWEEN 10 PRECEDING AND CURRENT ROW,比全分区扫描省得多
别让窗口任务和shuffle-heavy任务抢资源
单纯调参治标不治本。窗口计算密集型任务如果和大JOIN、GROUP BY混跑,不仅内存争抢,spill文件还会抢同一块磁盘带宽,延迟直接翻倍。
- Spark 3.0+必须绑定
resourceProfile,YARN场景要提交到独立队列(如window-queue),并配yarn.scheduler.capacity.root.window-queue.maximum-capacity=40 - Spark UI里核对:
Stage Details → Resource Profile ID非default,且executor分配的cores/memory符合预期 - PostgreSQL里,如果用PgBouncer,确认
ignore_startup_parameters = work_mem已开启,否则SET LOCAL会被过滤掉
真正卡住性能的,往往不是参数没调够,而是PARTITION BY字段选得窄、资源没隔离、或者work_mem在连接池里根本没生效——这些地方一漏,调再大的内存也白搭。

















