Oracle数据库IO慢怎么办 性能优化实战方法解析

阿木 发布于 6 小时前 2 次阅读


那天我盯着那行跑了51秒的SQL,同事说,要不加个索引吧。

我没说话。

因为我清楚,就算索引建设得再精美,要是数据依旧在那块转速为7.2k转的机械硬盘上运转,那这个查询注定还是会卡顿。

我们总爱谈优化。

谈索引、谈执行计划、谈SQL改写。

谈了一整天,最后发现,慢的根本不是那条语句。

是磁盘。

什么是“命中”,什么是“没命”

大家都说缓存命中率要到99%。

99%听起来好安全。

可剩下的那1%,偏偏在你业务最高峰的时候砸过来。

IO延迟从0.1ms跳到70ms。

事务提交像在等一个迟到的人。

您前往查看V$SESSION_WAIT,其内容全部都是log file sync。

那一刻你忽然明白:

数据库从来不怕慢,它怕的是时快时慢。

你知道内存里住着谁吗

Buffer Cache。

SGA里那块最贵的地皮。

LRU算法仿若一位精明的房东,它常常会将最近使用过的房客留在客厅,而把那些不经常前来的房客驱赶至磁盘去睡觉。

但房东也有看走眼的时候。

进行一次全表扫描,能够将整栋楼里的租客全部替换一遍,热数据被驱赶出去,冷数据被邀请进来。

SELECT
    (1 - (phy.value / (cons.value + db.value))) AS buffer_cache_hit_ratio
FROM
    v$sysstat phy,
    v$sysstat cons,
    v$sysstat db
WHERE
    phy.name = 'physical reads'
    AND cons.name = 'consistent gets'
    AND db.name = 'db block gets';

这叫缓存污染。

比你房东更不讲理的是Compaction。

在存算分离的架构当中,只读节点才刚刚将数据捂热乎,紧接着后台进行了一次合并,随后版本号就发生了改变。

缓存凉了。

查询又开始去对象存储拉数据,一秒变三秒。

真的有命中和没命中的世界

有人说SSD已经很快了,要缓存做什么。

可你测过吗?

NVMe是微秒级,机械盘是毫秒级。

差三个数量级。

而内存呢?

那是纳秒级。

有没有的问题。

为什么90%的DBA在调缓存,10%在调命

因为调大小最简单。

innodb_buffer_pool_size由4G调整为8G,敲下回车键,命中率提升了3个百分点。

你甚至可以炫耀:我今天优化了数据库。

ALTER DATABASE DATAFILE 'datafile_name' RESIZE 1024M;

可那些点没涨上去的3%呢?

藏在业务逻辑里。

藏在一条根本不走索引的Join里。

# 示例命令,使用rsync工具进行文件备份
rsync -avz /path/to/source /path/to/destination

藏在凌晨两点那个没人敢动的存储过程里。

关于IO抖动这件事

读这篇笔记的你,大概率被“尖刺”折磨过。

超融合平台上,IO曲线像心电图。

看起来平均延时还在能够忍受的范围之内,然而,当那根针被扎下去的时刻,前端订单竟然没法下单,产线指令居然发不出去。

你不是在优化性能。

graph TD;
    A[检测到磁盘故障] --> B[隔离故障磁盘]
    B --> C[更换新磁盘]
    C --> D[系统自动开始数据重建]
    D --> E[验证重建成功并重新加入存储池]

你是在消除不确定性。

当你调整shared_buffers的时候你在想什么

PostgreSQL建议设到总内存的25%。

Oracle说db_cache_size要多大你看着办。

AWS说交给自动管理吧。

自动管理当然省心。

# 在Linux环境下使用dd测试磁盘写入速度
dd if=/dev/zero of=testfile bs=64k count=16k conv=fdatasync

可省心的代价是什么?

是某个深夜,AMM把缓存调小了,把操作系统空闲内存调大了。

它以为那是空闲。

你的业务却以为那是灾难。

新硬件不一定治百病,但它能治穷病

我们这一代DBA,太习惯“凑合”了。

# 使用iostat命令查看磁盘IO统计信息
iostat -dx /dev/sda

习惯于在机械盘之上进行雕花操作,习惯于在虚拟化层面之中寻觅原因所在,习惯于去说服自身“瓶颈之处在于SQL,并非在于硬件”。

直到有人把全NVMe架构拍在你面前。

直到你看到那条跑了51秒的查询,0.1秒就出结果。

那一刻你忽然觉得:

过去那些年不是在调优,是在赎罪。

经验要不要写成程序

zCloud在做一件事:

将老DBA脑袋里的,“这里应当增加索引”,以及“那里不应该进行变动”,撰写成知识图谱。

AI说,这条SQL慢,改吧。

有的老DBA讲,速度是慢了些,然而这可是凌晨三点才生成的报表,而且一个月才运行一回,千万别去改动它,假设改动后出了问题,究竟谁来承担责任呢。

经验不是规则。

经验是:我知道什么时候该打破规则。

你调过redo log的位置吗

把控制文件放一块盘。

把redo log组放另一块盘。

把归档扔去第三块。

这叫物理分离。

十几年前的老手艺了。

现在的云数据库早就不让你碰盘符了。

你只能在“性能保障”那一栏,默默选个更高IOPS的套餐。

不是你不会调了。

BEGIN
  DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT;
END;
/

是你没权限调了。

所以,缓冲区缓存到底为什么重要

因为它站在内存和磁盘中间。

替99%的查询挡住那1%的灾难。

ALTER SESSION SET sql_trace = true;

它不是最快的那条路。

但它是最稳的那堵墙。

写在最后

tkprof /path/to/tracefile.trc /path/to/outputfile.txt

那天我还是加了个索引。

因为51秒降到0.1秒那个案例,我用的是全NVMe。

可我手里这台机器,磁盘还是十年前的老伙计。

加完索引,查询从3秒变成1.8秒。

EXEC DBMS_STATS.GATHER_DATABASE_STATS;

同事说,哟,优化了40%呢。

我没告诉他,1.8秒对磁盘来说已经是极限了。

我同样没有将此事告知他,只要这儿的这片盘在今晚出现哪怕是一个扇区坏掉的情况,那这百分之四十便彻头彻尾是个笑话。

数据库优化做到最后,

不是和技术斗,

是和预算斗,

是和“够用就好”斗。

SELECT file_id, name, bytes, blocks, io_bytes_read, io_bytes_written 
FROM v$datafile;

但我想了想,什么也没说。

只是默默把监控页面的缓存命中率,拖到了仪表盘正中央。