对于SQL,我们一般都说SQL审计,SQL优化,很少谈SQL监控。确实也是,SQL是很难监控的,因为一个复杂的系统中,每天SQL的执行次数高达千万级别,甚至数十数百亿,执行不同SQL的数量也可能高达数万数十万。如果大量的SQL是动态生成的或者没有使用绑定变量,那么可能在几分钟内就有数万条不同的SQL在执行。
在这样的情况下,如果我们需要开发一个通用性的产品用于做SQL监控是十分困难的。当然如果我们的业务系统相对比较稳定,需要监控的SQL数量相对稳定,针对这些SQL做针对性的监控也是比较容易实现的。而事实上,对于大多数企业来说,我们需要监控的数据库系统有上百甚至上千套,业务系统也在不断发生变更,在这种环境下,要实现通用的SQL监控确实还是有难度的。
对于DBA来说,也会有一定的SQL语句监控的需求,也都会掌握一些SQL语句监控与分析的技巧。对于Oracle数据库的DBA来说,我们已经十分习惯于通过AWR报告的TOP SQL相关内容来分析SQL的运行情况,发现存在问题的SQL。不过这种分析只能算SQL优化,而无法称之为SQL监控。
今天我们来探讨一下SQL监控的问题,随着硬件、云平台、数据库技术以及应用架构的不断优化演进,一些完全因为硬件资源或者数据库配置等引发的数据库问题的比例相对较少了,而因为SQL引发的问题在运维中的占比越来越高。对于SQL的监控需求是一直存在的,而且需求的种类也五花八门。前阵子有个客户提出需要了解随意一条SQL在某个时间段内的精确执行次数,问我们的D-SMART是否支持。另外一个客户问我D-SMART是否支持对任意一条SQL的执行计划变化进行跟踪,发现问题及时报警。
实际上SQL监控的目的依然是及时发现系统可能存在的风险。我和第一个朋友聊了聊他需要做如此精确的监控的目的是什么,他也说不出一个所以然来。实际上这个需求最好从应用的角度去做,在应用系统的模块中通过钩子进行统计的成本是最低的,从数据库去做可能成本太高。如果要从数据库的角度去统计,其精准度就要大打折扣了,因为数据库的内存中保存的SQL统计信息并不完整,因此我们去采样的时候会有误差。当某条SQL有一定时间没有执行的时候,很可能会从内存统计缓冲区中被清除,下一次再出现的是可能从头统计了。目前我们的TOP SQL采集工作也是5分钟进行一次,对这段时间内比较活跃的SQL进行一次统计。因为大型系统中的SQL数量可能会十分庞大,为了避免给生产系统带来太大的负载,这种采集也必然是轻量级的,只采集一些十分重要的TOP SQL的详细信息。
至于第二个需求,如果我们要对全量的SQL进行执行计划的跟踪,那肯定是不现实的,如果系统中存在几万条SQL,几十万个执行计划,采集一次的成本开销之大,对于一些并发量较高,并且业务对SQL执行延时的稳定性要求较高的系统来说,是无法承受的。
Oracle数据库的SQL语句都是存储于共享内存的CURSOR结构中的,而不少开源、国产数据库并不使用全局共享CURSOR的方式,CURSOR仅在会话内共享。因此采集SQL语句与执行计划的接口并不十分完善,有些数据库甚至还要开启一些特殊的跟踪功能才能实现。针对不同的数据库产品,我们需要采取不同的手段来采集TOP SQL,因此SQL监控的实现方式还是需要仔细去设计的。
另外一点,我们做SQL监控的目的并不是SQL监控本身,SQL监控的目标是防止SQL出现异常,从而导致数据库系统出现问题。因此我们不能把SQL监控当初目标,而是把SQL监控当成一种手段和方法。因此在一个系统中,监控某个时间段内某条SQL的精确执行次数在绝大多数场景中没有任何意义,我们只需要知道某些可能影响系统的SQL语句的大致执行数量、平均每次执行的开销以及执行次数与开销的历史波动情况,就足以支撑我们所需要的运维分析场景了。
而某条SQL语句的执行计划发生了变化,如果其执行成本并无增加,对数据库的稳定运行并无太大的影响,那么这种变化我们也无需实时发现,只要在定期的审计中有所发现,并能够分析出其存在的潜在风险就可以了。而因为执行计划的变化而导致了系统负载过高,系统性能下降,那么我们从其他一些方面也可以观察到。我们利用数据库可观测性的一些其他侧面能够发现此类问题就可以了。比如我们可以通过整个系统的逻辑读/物理的突然增加,CPU使用率的增加,活跃会话数的增加等相对容易观察到,并且监控成本比较低的可观测性指标也能够发现因为SQL执行计划变坏导致的问题,并能够通过分析定位,快速发现是因为SQL执行计划变坏导致了该问题。那么我们也就能解决这个问题了。
比如说在D-SMART中采用了关键SQL平均逻辑读突增与每秒逻辑读数量超出正常水平等两种方式来发现相关的问题。我们以关键SQL平均逻辑读突然增加的告警来看看D-SMART是如何分析这个问题的。
从SQL的历史分析上看,确实出现了平均每次逻辑读突变的情况。我们再来看看SQL的执行计划,是不是出现了多个执行计划。
从分析上看,确实出现了两个不同子游标,其中一个游标的执行成本明显大于另外一个。正是因为这个问题,导致了刚才那个告警的出现。这种方式是针对关键SQL的,关键SQL是一个系统中对应用可用性或者SLA有着关键影响的SQL,我们可以在每个采样周期都对其进行监控。因为一个系统中的关键SQL的数量不会很大,因此这种专项监控的成本也不高。
而如果出问题的并不是关键SQL,而是随便哪一条SQL,突然因为统计信息不准确或者说表数据量的变化,亦或是系统变更后出现了应用的BUG,从而引起了执行计划的变化,进而导致了系统资源不足,引起关键SQL因为系统资源不足(内存,CPU,IO等)而引发了性能问题。这种情况也是十分常见的。如果这条SQL出问题还没有触发系统资源不足,从而导致核心业务故障,那么这个问题并不一定需要马上被捕捉到,并且进行处置。
只需要在定期的SQL审计(比如每周)中发现这个问题,就完全可以解决。如果比较严重了,可能会导致系统故障,那么我们还是需要尽可能早的捕获到此类问题。在D-SMART中我们针对逻辑读突增、物理读突增、R队列突增、活跃会话数突增、同一条SQL的并发执行量达到某个阈值(此类SQL执行计划异常后必然出现执行时间过长,如果对系统产生较大影响,则大概率会出现多个SQL同时执行的情况出现)等,都会产生告警。并且在这些告警中,都可有执行计划发生变化的诊断路径,可以用于根因溯源。这样就采取了一种迂回策略,从一个侧面解决了此类问题的预警问题。