bigywater.tech
PostgreSQL · 12

PostgreSQL shared_buffers 该设多大:pg_buffercache 看缓存、全表扫描的环形缓冲、命中率和 pg_prewarm 实测

“PostgreSQL 的 shared_buffers 该设多大、怎么看缓存命中率、重启后为什么变慢” 都可以用 pg_buffercache 和 EXPLAIN (BUFFERS) 直接看到。这篇在本机自己起一个 PostgreSQL 16.15,用 120.5 MB 的表验证 read 和 hit 的区别、全表扫描的环形缓冲、命中率的算法,以及 pg_prewarm。

33 / 15424
全表扫描后留在 shared_buffers 里的页数 / 整张表的页数(环形缓冲)
95.4% 对 44.3%
2 万次随机点查的索引页命中率 / 堆页命中率
31857 → 0
shared_buffers 从 16MB 到 256MB,第二遍点查的 read 数

read 与 hit

实测 · 本机执行输出
  第 1 次:25.21 ms;Buffers: shared hit=3 read=3623;I/O Timings: shared read=6.482
  第 2 次:17.98 ms;Buffers: shared hit=3626
  表和索引占了多少个缓冲区:t 3078 个,t_pkey 550 个

Buffers 里 read 是向系统要页,hit 是命中共享缓冲区;重启后第一次全是 read。

全表扫描

实测 · 本机执行输出
  全表扫描:78.15 ms;Buffers: shared read=15424
  扫完之后 t 在 shared_buffers 里有 33 个缓冲区(整张表有 15424 个页)
  再扫一次:67.00 ms;Buffers: shared hit=33 read=15391(仍然大部分是 read,因为上一次的页没有留下来)

大表的顺序扫描用环形缓冲,只占几十个缓冲区,不会冲掉热数据。

命中率

实测 · 本机执行输出
  2 万次随机点查:0.99 s,平均 50 μs;缓冲区里 t 有 11149 个,t_pkey 有 2741 个
  heap_blks_read = 11149,heap_blks_hit = 8851,idx_blks_read = 2741,idx_blks_hit = 57260;堆页命中率 44.3%,索引页命中率 95.4%
  同样的 2 万次再来一遍:0.85 s,平均 43 μs

pg_statio_user_tables 的 heap_blks_hit / (read + hit);索引页命中率通常远高于堆页。

shared_buffers 大小

实测 · 本机执行输出
  shared_buffers     第 1 遍耗时    read     hit     第 2 遍耗时    read     hit
            16MB       0.87s   32059   48264       0.97s   31857   48464
            64MB       0.91s   17221   63102       0.90s   13502   66819
           256MB       0.90s   13964   66359       0.81s       0   80321

工作集装不下时第二遍仍然大量 read;在系统缓存很大的机器上耗时差别不大。

pg_prewarm

实测 · 本机执行输出
  不 prewarm,第一次:29.95 ms;Buffers: shared hit=3 read=3623
  pg_prewarm(t_pkey) 读了 2745 个页,pg_prewarm(t) 读了 15424 个页,共 0.07 s;缓冲区里 t 有 15424 个,t_pkey 有 2745 个
  prewarm 之后第一次:21.46 ms;Buffers: shared hit=3626

重启或切换后用 pg_prewarm 提前把热表和索引读进缓冲区。

分步演示

缓冲区实测
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / PostgreSQL 16.15(Homebrew);每个实验自己 initdb 一个数据目录,端口 9261 起,只监听 127.0.0.1,不碰本机已有的 5432 上的实例;命令行工具统一用 LC_ALL=C 取英文原文,路径换成 ;计时用 time.perf_counter 或 EXPLAIN ANALYZE 的 Execution Time,数字每次运行会有小幅抖动;实验结束后整个数据目录删除。shared_buffers 默认 256MB(第四篇除外),关掉并行查询,开 track_io_timing;这台 macOS 上没有提权清不掉操作系统的页缓存,所以所有“冷”都只是 PostgreSQL 缓冲区为空,read 的代价远低于真实磁盘
    • 没有验证:真正冷的磁盘读(清掉系统缓存后);Linux 上 shared_buffers 与系统页缓存的双重缓存;huge pages;pg_buffercache 对多库的统计;checkpoint 时脏页写出的影响(见本系列后面的文章);PostgreSQL 其他大版本的缓冲区管理
    京ICP备2026067502号-1京公网安备11010502063487号