pg_stat_io是PostgreSQL较新版本中引入的一个系统视图,它第一次把数据库整个IO层面的活动做了系统化的统计。在此之前,DBA排查IO问题往往只能依靠操作系统的iostat、pg_stat_database中的blk_read_time等间接指标,很难区分IO到底来自普通查询、autovacuum还是检查点。pg_stat_io的出现改变了这个局面,它把IO按照数据来源、IO对象和操作类型三个维度切分,让IO消耗的去向一目了然。

pg_stat_io视图的核心结构
先看视图的基本结构。执行SELECT * FROM pg_stat_io;可以看到输出中包含三个维度的字段组合:backend_type表示IO的发起方,可以是client backend、autovacuum worker、background writer、checkpointer、startup、walwriter等;object表示IO操作针对的对象,取值包括relation(普通堆表和物化视图)、temp relation(会话临时表)、local relation(临时表所在专用缓冲池)以及wal(预写日志);context表示IO发生的上下文,比如normal、vacuum、bulkread、bulkwrite、wal等,不同context对应不同的缓冲区访问策略。
统计指标方面,reads、writes、extends分别记录读、写和扩展文件的次数,hits记录直接从shared_buffers命中而无需物理IO的次数,evictions记录因缓冲池满而将脏页换出的次数,reuses记录策略环缓冲区(环形缓冲)复用的次数,writebacks记录调用内核回写接口的次数,flushes针对WAL统计刷盘次数,extends时间、读时间、写时间等则通过waittime相关字段给出累计耗时。
这种多维度切分的设计价值在于:同样是缓冲池写入,backend自己写的页面和background writer写的页面含义完全不同,前者通常意味着系统压力大、后台写来不及,后者则是正常的后台刷脏。分开展统计后,这些信号可以被清晰地区分开。
关键字段详解与容易混淆的概念
evictions和reuses是两个最容易混淆的字段。evictions发生在sharedbuffers空间不足时,系统需要淘汰某个缓冲区,如果该缓冲区是脏页就必须先写回磁盘。如果查询使用了bulkread、bulkwrite或vacuum策略,PostgreSQL会为该会话分配一个256KB左右的小环形缓冲,用完后直接复用这些缓冲区而不再走全局淘汰逻辑,这个动作被计入reuses。简单说,evictions对应全局缓冲池的换页,reuses对应策略环缓冲的复用,两者都不一定伴随实际写盘,取决于页面是否为脏。
extends字段也值得特别关注。它统计的是文件扩展操作,即向表中插入数据导致文件需要增长。大表批量导入时extends会非常高,如果发现extends次数异常且伴随大量的文件系统层面的元数据操作,说明可能存在大量小事务频繁插入的问题,这时候batch模式插入或者调大wal的配置会有帮助。
writebacks则是另一个有意思的指标。PostgreSQL默认使用fasync风格的写入,writebacks统计使用了sync_file_range这类回写接口的次数,可以用来判断是否有大量未落盘的脏页积压在页缓存中,对评估掉电恢复风险有一定参考意义。
实战:用pg_stat_io定位常见IO问题
第一个场景是缓冲池命中率下降。可以用下面的查询快速计算命中率:
SELECT backend_type, object, context,
reads, hits,
round(hits * 100.0 / nullif(hits + reads, 0), 2) AS hit_ratio
FROM pg_stat_io
WHERE object = 'relation'
ORDER BY reads DESC;如果client backend的hit_ratio明显低于95%,首先要怀疑shared_buffers配置过小,或者存在大量顺序扫描把热数据挤出缓冲池的情况。结合context字段还能进一步判断:bulkread比例高说明大表扫描在用环形缓冲策略,这类扫描本来就不太污染缓冲池,属于正常现象。
第二个场景是检查点写压力过大。查看checkpointer或background writer的writes指标,如果writes持续增长且每次检查点触发时伴随明显的IO尖峰,说明checkpoint_completion_target设置过小或max_wal_size不够,导致脏页集中在检查点末期刷盘。适当调大max_wal_size可以让脏页摊平在两次检查点之间写出,削平IO峰值。
第三个场景是临时文件滥用。temp relation的读写如果很高,通常意味着work_mem偏小,排序、哈希聚合或者中间结果落盘了。可以搭配log_temp_files参数记录临时文件的使用情况,再结合pg_stat_statements找到tmp_blks_written大的语句进行针对性优化,比如增大work_mem、改写SQL减少排序量或者给相关表加合适的索引避免排序。
与操作系统监控配合使用
pg_stat_io给出的是数据库视角的统计,实际运维中建议与iostat或sar配合。一个典型的分析路径是:先用iostat确认磁盘util和await升高,再进数据库查pg_stat_io看是哪个backend_type在贡献IO。如果是autovacuum worker的writes很高,检查是否有长事务阻止了死元组清理,或者autovacuum_vacuum_cost_limit设置过低导致vacuum跑得太久;如果是walwriter或WAL相关的flushes很高,说明事务提交频繁,可以考虑同步提交参数synchronous_commit的调整或者应用端的提交合并。
另外需要注意,pg_stat_io的统计是累计值,分析时应该结合stats_reset时间戳,或者定时采集快照计算差值,pg_stat_io_view这类辅助工具或者自建的快照表都可以完成这个工作。对于云上RDS环境,如果控制台没提供该视图,也可以通过track_io_timing参数开启IO计时,让blk_read_time、blk_write_time等指标可用,作为降级方案。
总的来说,pg_stat_io把过去黑盒的IO行为拆解成了可查询、可量化的维度,是性能诊断工具箱里非常值得掌握的一个视图。建议在日常巡检中定期采集它的快照,建立基线数据,这样在故障发生时才能快速判断IO行为是否偏离了正常水平。
pg_stat_ioPostgreSQLIO性能分析修改时间:2026-09-05 00:14:38