“PostgreSQL 的 Sort Method: external merge Disk 是什么意思、work_mem 该调多大” 是慢查询里经常出现的疑问。这篇在本机自己起一个 PostgreSQL 16.15,用 100 万行的表对比 work_mem 对排序和哈希聚合的影响,验证 top-N 排序和索引能省掉什么,并演示怎么从日志里找到写临时文件的 SQL。
work_mem = 4MB:Sort Method: external merge Disk: 17672kB;耗时 258.80 ms;Buffers: shared hit=12352 dirtied=1777, temp read=2209 written=2223 work_mem = 64MB:Sort Method: quicksort Memory: 55827kB;耗时 221.52 ms;没有临时文件 work_mem = 256MB:Sort Method: quicksort Memory: 55827kB;耗时 219.56 ms;没有临时文件
放得下是 quicksort(内存),放不下是 external merge(写临时文件)。
work_mem = 64kB:Sort Method: top-N heapsort Memory: 27kB;耗时 102.39 ms work_mem = 4MB:Sort Method: top-N heapsort Memory: 27kB;耗时 100.11 ms
order by … limit N 只维护 N 行,work_mem 很小也不写盘。
有索引可用:-> Index Scan using t_r on t (cost=0.42..74038.74 rows=1000000 width=8) (actual time=0.006..22.989 rows=100000 loops=1) → 没有 Sort 节点: True;耗时 28.64 ms 关掉索引扫描:Sort Method: external merge Disk: 17672kB;耗时 258.66 ms
ORDER BY 的列上有索引,计划里没有 Sort 节点,也没有临时文件。
日志:LOG: temporary file: path "base/pgsql_tmp/pgsql_tmp<pid>.<n>", size 18096128
日志:STATEMENT: select r, id from t order by r
pg_stat_database(postgres):temp_files = 1,temp_bytes = 18096128(17.3 MB)log_temp_files 把每个临时文件连同 SQL 记进日志;pg_stat_database 累计。
work_mem = 4MB:Planned Partitions: 8 Batches: 9 Memory Usage: 8273kB Disk Usage: 23536kB;耗时 284.28 ms work_mem = 64MB:Batches: 1 Memory Usage: 65553kB;耗时 255.31 ms work_mem = 256MB:Batches: 1 Memory Usage: 65553kB;耗时 255.65 ms
HashAggregate 放不下会分批溢出到磁盘;work_mem 是每个节点、每个会话各用一份。