DBAtlas · 数据库运维图谱

IO 等待高 / 磁盘延迟高

系统正在等待磁盘 IO。首先区分负载是读密集还是写密集,然后深入到原因:buffer cache 不足、全表扫描、checkpoint 风暴、IOPS 上限或溢出到临时空间。

IO 是读密集还是写密集?

使用文件 IO 统计信息确定等待发生在读取端(从磁盘读取数据)还是写入端(redo/checkpoint/数据写入)。这会将决策树一分为二。

SELECT function_name, small_read_reqs+large_read_reqs AS reads, small_write_reqs+large_write_reqs AS writes,
       small_read_megabytes+large_read_megabytes+small_write_megabytes+large_write_megabytes AS mb
FROM v$iostat_function ORDER BY mb DESC;
  • 主要是读 IO
  • 主要是写 IO

读 IO 为什么高?

过多的物理读主要有三个原因:buffer cache 太小(工作集放不进 RAM)、查询执行全表扫描,或大型排序/哈希操作溢出到临时空间。

SELECT ROUND((1-(pr.value/(dbg.value+cg.value)))*100,2) AS buffer_hit_pct
FROM v$sysstat pr, v$sysstat dbg, v$sysstat cg
WHERE pr.name='physical reads' AND dbg.name='db block gets' AND cg.name='consistent gets';
SELECT sql_id, disk_reads, executions FROM v$sql ORDER BY disk_reads DESC FETCH FIRST 10 ROWS ONLY;
  • buffer cache 命中率低,工作集放不下
  • 查询执行全表扫描
  • 大型排序/哈希溢出到临时空间

写 IO 为什么高?

写入端的瓶颈要么来自周期性的 checkpoint/刷写短时间内使磁盘饱和(checkpoint 风暴),要么来自存储缺乏维持负载所需的 IOPS/吞吐量。

SELECT event, total_waits, ROUND(time_waited/100,1) AS sec
FROM v$system_event
WHERE event IN ('log file parallel write','db file parallel write','checkpoint completed')
ORDER BY time_waited DESC;
  • checkpoint/刷脏集中爆发(checkpoint 风暴)
  • 存储跟不上持续负载(IOPS 上限)

根本原因:buffer cache 不足

频繁访问的数据集(工作集)放不进 buffer cache,因此数据块不断被从磁盘重新读取。命中率低,物理读高。

根本原因:全表扫描

由于没有合适的索引,查询从头到尾扫描大表;这既导致大量物理读,又用无用的数据块污染缓存。

根本原因:排序/哈希溢出到临时空间

大型排序、hash join 或 group by 操作放不进工作内存,写入临时空间(temp/tempdb),产生大量读写 IO。

根本原因:checkpoint 风暴

脏页长时间累积,然后在短时间内批量写入磁盘;这些突发的写入浪潮会周期性地使 IO 饱和。

根本原因:IOPS / 吞吐量不足

存储缺乏满足负载所需读写请求的 IOPS 或带宽;队列深度和延迟持续偏高。

在 DBAtlas 中打开 →