Hash Join写磁盘主因常非work_mem不足,而是数据倾斜、统计信息过期或执行计划误选;须先用EXPLAIN (ANALYZE, BUFFERS)确认Disk Usage非零,再查pg_stat_progress_hash比值及TOP1频次是否超均值10倍,最后按操作粒度合理设置work_mem。

Hash Join写磁盘了,先确认是不是work_mem真不够
看到日志里反复出现 writing to disk due insufficient memory,别急着调大 work_mem。真正拖慢 Hash Join 的,可能是数据倾斜、统计信息过期,或者执行计划本身选错了连接方式。
第一步必须做:用 EXPLAIN (ANALYZE, BUFFERS) 跑一次慢查询,重点看 Hash 节点的 Disk Usage 字段——如果为 0,说明根本没落盘,调 work_mem 没意义。
第二步查 pg_stat_progress_hash(PostgreSQL 12+):
-
hash_probe_total_buckets / hash_buckets_used比值 > 3?说明哈希桶严重稀疏,大概率是work_mem太小被迫建了太多桶,内存被浪费而非不足 - 同时跑
SELECT key, COUNT(*) FROM table GROUP BY key ORDER BY 2 DESC LIMIT 5,TOP1 频次 > 平均值 × 10?那是数据倾斜,加内存也救不回来
work_mem设多少才合理,不是越大越好
work_mem 是每个操作(一个 Hash Join、一个 Sort、一个 DISTINCT)能独占的上限,不是整个查询或整个会话的总和。设高了容易引发 OOM 或 swap,设低了又频繁落盘。
估算下限可粗略按驱动表来算:(行数 × (Join 键长度 + 8)) × 1.5(1.5 是哈希填充因子预留)。但实际推荐从保守值起步:
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
- 会话级临时生效最安全:
SET LOCAL work_mem = '4MB'; - 逐步试到
'16MB'→'32MB'→'64MB',每次只改当前事务 - 避免全局设置,尤其当
max_connections较大时(比如 200 连接 × 64MB = 12.8GB 理论峰值)
注意单位:写成 '64M'(少个 B)会被静默转成 64 字节,直接崩;必须是 '64MB' 或 67108864。
为什么调了work_mem还是写磁盘?并行和嵌套操作在偷吃内存
即使你给单个 Hash Join 分配了 64MB,它仍可能落盘——因为 PostgreSQL 按“每个哈希操作”单独分配,而一个查询里常有多个消耗 work_mem 的环节:
- 同一查询含 Hash Join + Sort + DISTINCT?三者各自申请
work_mem,总开销是三倍 - 开了并行(
max_parallel_workers_per_gather = 4)?每个 worker 进程都独立申请work_mem,主进程的pg_stat_progress_hash看不到 worker 状态,极易误判 - 嵌套 Hash Join(比如子查询里又有一个 Hash)?每个层级都算一个独立操作
shared_buffers 和 effective_cache_size 对 Hash Join 完全无效——它们不参与哈希表构建,调了也没用。
Hash Join不是万能解,该换策略时就换
PostgreSQL 16 的优化器通常能自动选对连接方式,但以下情况它可能选错,或你该主动干预:
- 驱动表极小(/*+ NestLoop(table1 table2) */(需
pg_hint_plan)试试 - 两表都很大、Join 键重复度低、内存充足?Hash Join 合理,但得确保驱动表是小的那个——用
EXPLAIN看哪个表在 Hash 节点下方(即 Build side) - Join 键存在大量 NULL 或重复值?Hash 效率骤降,考虑预过滤或改用 Merge Join(需两边都有排序索引)
最后提醒一句:Hash Join 的性能瓶颈,90% 不在算法本身,而在内存配置与数据分布的匹配度。盯着 Disk Usage 和 pg_stat_progress_hash 看,比盲目调参靠谱得多。

















