SQL Server 2000 数据库IO优化 高延迟卡顿排查教程

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


昨晚我删了一个索引。

并非是手滑,而是注视着那条持续了8秒的查询,瞬间察觉到,我们长久以来斥责的“慢SQL”,实际上背负了过多本不应属于它的责任,真正的致使变慢的因素,是隐匿于I/O路径之中那个佯装顺从的缓存。

你是不是也在“假装优化”?

大多数人遇到数据库慢,第一反应是什么?

加索引。改SQL。甚至清缓存。

像个消防员,看见冒烟就喷水,从来不看火源在哪。

那么结果究竟怎样呢?索引构建了二十几个,然而业务却并未快出多少,写入操作反倒卡顿得如同播放PPT一般。防病毒软件处于开启状态,扫描策略却没有将数据目录排除在外,每秒会有成千上万次的读写操作,被它从起始一直过滤到末尾。

SQL Server has encountered ## occurrence(s) of I/O requests taking longer than 15 seconds to complete on file [##] in database [##] (#). The OS file handle is 0x00000. The offset of the latest long I/O is: 0x00000.

你以为是查询写得烂。

其实是I/O请求在排队,而排队的那个队伍,根本没动过。

我们被“15秒”骗了太久

SQL Server存在一个名为MSSQLSERVER_833的错误,一旦I/O请求的时长超出15秒即进行报错。

15秒啊。在计算机的世界里,这是三个世纪。

然而,绝大多数人瞅见此错误,其第一反应乃是:磁盘坏掉了?赶忙寻运维去更换硬盘。

鲜有人去问,为何在这15秒当中,后续的请求始终处于被服务的状态,偏偏仅有最开始的那一个,却被遗忘掉了呢?

好像是在排队去买奶茶。前面的那一个人始终站在那儿,然而店员却不间断地招呼后面的人:“您好呀,请问您要点些什么呢?”。

这不是磁盘慢。

存在于I/O路径当中的某一组件,即驱动、控制器以及固件,在蓄意“饿死”陈旧请求。

而你的数据库,就这样饿着肚子,还在硬撑。

缓存不是原罪,骗人的缓存才是

什么是安全的写入缓存?

SQL Server得要把数据写入缓存之中,机械硬盘其速度极为缓慢,要是不使用缓存的话,那可真能将人急死呀。

然而问题就此出现了:缓存接收了数据,告知SQL Server“已经写完了,你可以放心了”,接着自身将数据揣入囊中,计划稍后再存储到磁盘。

这会儿,啪的一下,断电了。要么,内存奇偶校验出现报错情况了。要么,是你手贱去按了重启按钮。

兜里那张还没存进去的“支票”,没了。

重启SQL Server,而翻开账本,日志之中明明记载了这笔交易,钱在哪里,数据又在何处!

这不叫缓存。这叫诈骗。

真正的“稳定介质”,其实是个很卑微的要求

控制器为什么需要电池?

你可能会觉得:买个UPS(不间断电源)不就完了?

微软说:不够 。

就算并非断电,却存在着一万种致使死亡的方式,比如硬件信号发生故障,操作系统出现陷阱,甚至于有人动作迅速,在“正在关机”尚未完成转圈之际按下了Reset键。

真正称得上企业级别的写入缓存,必须要达成这样的要求:无论你是以何种方式走向终结的,你放在口袋里所揣着的那张支票,在系统恢复正常运行之后,都能够被找寻出来。

板载电池备份。镜像内存。拦截RST总线信号。ECC纠错 。

这些东西,你的存储控制器,有吗?

不知道?那你是真的胆大。

SSD时代,旧经验正在悄悄杀你

曾经运用机械硬盘时,我们竭尽全力将随机写予以合并,使之成为顺序写,简直渴望磁头始终朝着一个方向进行转动。

现在用NVMe SSD了,还在用这套。

那么结果究竟如何呢?人家固态硬盘内部存在着几十个并行通道等待着你去将它们喂饱,然而你却把所有的请求排列成一列,生怕它会累着。

更为离谱的是,存在学术方面的研究表明,在某些特定的情形之下,于NVMe之上运行并未经优化的SQL,其性能竟然会比机械硬盘还要糟糕。

不是SSD不行。

是你拿着法拉利,却只敢挂一档,还怪车没劲儿。

你还在用OFFSET翻页?

有时候慢,真的只是因为蠢

深分页。OFFSET 100000, 10。

数据库老老实实数了十万行,扔掉,把最后十行给你。

你问它为什么慢。它说:你让我数的。

这不是I/O的问题,这是脑子的问题。

但更可怕的是那些“看起来没问题”的查询。

索引已添加,执行计划已采用索引,字段区分程度尚可,测试环境瞬间回复。

上线就崩。

因测试环境仅有一万条数据,全表扫描犹如眨眼间之事。线上存有五千万条数据,优化器经计算后心想:咦,回表成本似乎比全表扫描还要高些?——那就采用全表扫描方式吧!

索引在那儿摆着,它就是不用的那种感觉,像极了爱情。

防病毒软件:看不见的I/O杀手

我说个数据,你别害怕。

许多数据库服务器的数据存放目录,在初始状态下处于防病毒软件的实时扫描清单之中。

你觉得它如在安安静静地开展业务,实则每一次写入,均有一名保安反反复复地予以检查。

并非是不能够去安装杀毒软件,而是因为它属于企业级数据库,所以你必须要为它划分出专门的区域,这就如同重要人物外出行动时呀,当车队经过的那些路口呢,并非是采取封路的举措,而是要提前进行清场处理。

不过,大部分人的操作为,完成数据库安装后,进行杀毒软件安装,采用默认设定,接连不断地一直点击下一步。

然后半夜三点,报警响了。

你注视着慢查询日志,怎么都料想不到,凶手竟是那个模样乖乖的、颜色呈现绿色的、每日都会进行病毒库更新的小图标。

所以,到底怎么办?

我不是来给标准答案的。

存有标准答案的网络各处皆是如下内容:关闭磁盘缓存,运用电池进行备份操作,实现分区对齐,开启TRIM功能,开展查询改写工作,进行连接池预热。

你收藏过,我也收藏过。然后呢?

我想说的是另一件事。

数据库运行缓慢,绝非是由于单独一个原因所导致的。它是多方因素共同作用而产生这种状况的结果,这些因素涵盖了查询方面,索引方面,缓存方面,控制器方面,驱动方面,固件方面,杀毒软件运行方面,甚至还包括隔壁团队所执行的那个长事务。

但我们都太着急了。着急定位,着急下结论,着急甩锅。

有很少的人愿意挨着服务器就座,将性能计数器开启,瞅着那条处于平稳状态的磁盘队列曲线,安安静静地等着它陡然间向上提升,随后问上一句:

“刚才那一秒,发生了什么?”

今天下午我把那个索引删了。

仍然是查询比较慢,不过慢得很实在了。不存在那种佯装优化的索引,不存在那种骗人的缓存。

I/O错误日志还在滚。

15秒。16秒。14秒。

我看着这些数字,第一次觉得,它们不是在控诉,只是在求救。

而我们这些做数据库的人,本该是听到求救声就跑过去的那一个。

而不是等到它喊了15秒,才回头看一眼。