前言
判断查询的性能就是看查询执行的时间,这个时间针对不同的业务要求上也有差异。在同一时间内SQL执行的越快,执行的SQL就越多,完成的业务逻辑就越多。同样一个业务场景不同的架构设计、数据库表索引设计,由不同的人来做效果是不同的,有的人可以用很低的成本,RDS规格,ECS规格跑出很高的性能。最好的情况是自顶向下了解业务,以及每个业务涉及的SQL,这样就能厘清业务和数据库负载的关系;也能找到短板,并对短板做有针对性的优化;全链路压测就是做的这个事情。另外也可以借鉴xtrace,strace等理念在分布式环境中做全链路的监控,阿里云已经有这样的产品叫链路追踪,可以清楚地监控从应用组件到基础组件,哪一个环节耗时最长,哪一个环节报错,详细请参考文档 https://www.aliyun.com/product/xtrace。全链路监控和全链路压测是值得大多数系统学习的。
下面针对数据库的各种导致SQL慢的排查思路,原因和解决方法进行阐述:
实例达到瓶颈
如果监控比较细微或对响应时间比较敏感的话,瓶颈很容易被监控到,达到瓶颈时一般可能有以下几种因素:
- 随着业务的增长而没有扩容,总有那么一天系统变慢;
- 随着时间的变化,大量的磁盘擦写或快过保的机器性能有损耗,也会达到瓶颈;
- 随着时间的累计,数据只增加不清理,表的大小也不断增加,有可能原来不慢的SQL变慢,如:索引缺失;可以借助自治服务诊断。
控制台路径是选择“云数据库RDS”->选择“实例列表”->点击实例链接,进入实例页面->选择“自治服务”->选择“资源监控”,详细参考 https://help.aliyun.com/document_detail/95667.html 。如果资源使用利用率各项指标都100%,可能是实例达到了瓶颈,这时候建议升级实例规格,方法参考 https://help.aliyun.com/document_detail/96061.html 。
判断实例有没有达到瓶颈,比较好的方法是先找到实例的性能基准值,先用sysbench或其他测试工具构建基准测试,当不管怎么增加压力,数据库的性能再也上不去时说明基准值已经出来了,在复杂场景下的QPS/TPS响应时间很少会超过基准值的。
版本升降级
数据库的版本升级可能会导致SQL执行计划发生改变,执行计划查询类型依次从好到坏的顺序是“system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > all”(官方链接 https://dev.mysql.com/doc/refman/5.6/en/explain-output.html#explain-join-types ),查询类型从“range -> index”,因为SQL的请求变慢,业务又不断重试请求,导致SQL并行查询比较多,进而影响应用线程释放慢,导致应用连接池耗尽,影响整个业务。查看近期有没有修改过参数的控制台路径是选择“云数据库RDS”->选择“历史事件”,详细参考 https://help.aliyun.com/document_detail/131008.html ,如下图所示:
参数调整
参数buffer_pool_instances/join_buffer_size/AHI等的变化也会导致性能变慢。关于这方面的文章比较多,这里不一一赘述。查看近期有没有修改过参数的控制台路径是选择“云数据库RDS”->选择“实例列表”->点击实例链接,进入实例页面->选择“参数设置”->选择“修改历史”,详细参考 https://help.aliyun.com/document_detail/131008.html ,如下图所示:
缓存失效
缓存的设计在架构上很好地承担了大量的查询,但并不能保证缓存命中率100%,如果缓存失效,也会有大量的查询涌到数据库端,导致性能下降。从数据库表现来说,看到各方面的资源(通常是CPU)打满,QPS/活跃线程飙的非常高。这样的情况RDS MySQL可以用SQL限流、打开线程池、语句并行队列、Fast Query Cache等可以缓解,详情参考https://help.aliyun.com/document_detail/130306.html 。目前数据库自治服务DAS,可以提供自动调参/自动扩容/SQL自动优化/SQL自动限流的工作,详情参考 https://help.aliyun.com/document_detail/164859.html 。
批量操作
如果有大批量的数据导入、删除、或拖数据的情况。
批量数据导入
这种情况可以从磁盘空间,或SQL洞察/慢查询里找到对应语句。如从binlog的大小,正常情况每个binlog问卷大小是500MB,如果有超过500MB的,就可以看是否有异常情况。
也可以从监控上看哪部分的空间有变化。
如果有批量数据导入IOPS上也会增加。
事务数也会增加。
InnoDB的写入量也会增加。
日志文件的写入也会增加。
InnoDB层的写入也会增加。
批量数据删除/回收
这种情况可以从磁盘空间,或SQL洞察/慢查询里找到对应语句。
可以看到truncate table时select 1都很慢。
拖数据
这种情况可以通过监控指标的变化或SQL洞察/慢查询里找到对应语句。
未关闭的事务
如果某个任务突然变慢,应该考虑是否有锁阻塞的问题。可以通过“如何定位长时间未关闭的事务和处理方法”这篇文章找到未释放的锁,应通过更快地释放锁来改善。如下图CPU和IOPS的利用率并不高,但应用拥堵,MySQL的活跃会话上涨就是存在未关闭的事务导致的。
未提交事务:
定时任务
如果负载随时间有规律性变化,则瓶颈随负载有规律性地变化,很大可能是定时任务引起的,如图所示:
SQL异常
查询慢有很多种原因导致,这种情况可能是由于库表结构设计不合理,或索引缺失,或扫描行数太多,或不常用到的查询条件导致,这种情况需要开发人员修改。
影响SQL语句执行的因素大概分为以下几类:表有哪些索引、存储特性、数据库引擎特性、查询条件的区分度、结果集大小、表的数据量、CPU时间。关于这一点已经讲的比较多,详细可以参考阿里云数据库最佳实践 https://yq.aliyun.com/live/1938 。
此外还可以使用数据库自治服务优化慢SQL,可参考https://help.aliyun.com/document_detail/167895.html。
业务场景发生改变
如何确定业务场景发生了改变呢?有两种可能:
1. 应用进行过发布
应用有没有进行过发布,需要看下应用的部署日志或发布系统可以查到痕迹。
2. 没发布,功能早上线,但不经常用,某天用户点了某个功能。
如果想确切定位同时段的SQL是否一样,就需要打开审计日志。打开审计日志的方法参考文档 https://help.aliyun.com/document_detail/96123.html 。同时段的SQL可以跟昨天同时间对比,或上周同时间对比。借助SQL洞察的SQL分析功能,或者更方便地用DAS专业版的“SQL对比”/“来源统计”。发现和没有问题时间段的SQL,找到来源即可。
或用DAS数据库自治服务的"一键诊断",路径参考https://help.aliyun.com/document_detail/99478.html。
扫描行数多
路径地址:阿里云控制台->选择对应数据库引擎->找到对应实例,点击“实例ID/名称”->选择“SQL洞察”或“自治服务”里的“慢SQL”
多表join
这种情况可以通过监控指标的变化或SQL洞察/慢查询里找到对应语句。
索引不合理
例如:
全表扫描
全表扫描一般发生在索引不合理或没有WHERE条件的SQL语句中,索引不合理好解决建立合适的索引就可以了,但对于没有WHERE条件的SQL语句发生时可以kill或降级业务解决。没有WHERE条件但SQL语句是高风险SQL,建议分批执行或放在业务低峰期执行,当然了尽量带上WHERE条件。如下图就是不带WHERE条件的,在DAS控制台/慢查询/SQL洞察等都可以找到。
CPU达到瓶颈
CPU在系统中相当于大脑,当CPU达到瓶颈后调度IO等就慢,也会导致慢SQL产生,这种情况可以从监控指标上看出。如
IO慢
IOPS达到瓶颈
如果慢SQL里出现DML,很大程度是IOPS利用率较高,如:
可以从SQL洞察里找到慢SQL:
也可从慢日志明细看到:
刷脏导致的IO慢
MySQL触发刷脏的时机有:RedoLog满,内存不够用,内存刷脏过程中的额外开销。这种情况可能会触发Buffer Pool的锁
lnnoDB缓存读命中率,使用率,胆块率(
(%)
120
80
2020-12-2816:51:00
缓冲池的读命中率(%)
99.98
n1
20
缓冲池的利用率(%)
97.92
缓冲池胆块的百分率(%)
22.48
21:00
18:00
14:00
15:00
16:00
17:00
19:00
20:00
22:00
23:00
缓冲池的利用率(%)
缓冲池脏块的百分率(%)
缓冲池的读命中率(%)
风
业务场景发生变化
业务进行过发布,或有不经常访问的业务突发访问比如ad-hoc类等,从监控指标上可以看到异常。
查看历史
近1小时
发起诊断
近12小时
近6小时
2020年12月28日22:47:09
2020年12月28日21:47:09
健诊断
自治中心neW
危险:1警告:0
性能趋势
贤温监控
实时会话
SQL分析
死锁
实时性能
大中务:当前无大务详情
当前时段光新未发生死铺
大会话:14条详情
实例会话
性能洞柴"ew!
话求分析
资无诊断
会话快国
全量SQL
sQL
慢日志
快丽开关:未开启会话快服前往
全HSQL要开启全量SOL高
QPSAVG:269.3MAX:4591.2
CPU用本:AVG:18.7%MAX:
魔SQL款量:6查看
级版前往
开启
100.0%详情
环比地长率:-96.30%上一个
SQL洞亮和审计
网士对长率:0.00%(昨天同村间
段情SQL技量为O)
时段AVG:7268.5)
需要优化的SQL模板校品:无
内存机用率:AVG:65.3%
MAX69.8%
法获取数拼
同比:长半:2780.08%(昨天同
空间分析
时间段AVG:9.3)
IOPS使用率:20.2%
该间后
全量SCL
模SeL
容量评估
锁分析
空间使用
附盘使用率:10.88%详情
实例告誉
剩会可用空间:1.74TB
近一周日均墙长量:164.18GB
性能快照
总结
哪些可以帮助我们定位慢SQL?
- 监控指标
对比两个时间段的监控指标的差异,如资源层面的差异,引擎层面的差异,选择“云数据库RDS”->选择“实例列表”->点击实例链接,进入实例页面->选择“监控与报警”->选择“资源监控”/“引擎监控”,下面看下各个指标的含义:
监控项 |
含义 |
说明 |
磁盘空间 |
实例的磁盘空间占用历史趋势,单位GB |
|
IOPS |
RDS实例的IOPS(每秒IO请求次数) |
|
连接数 |
当前总连接数 |
|
CPU使用率 |
RDS实例CPU使用率(占操作系统总数) |
|
网络流量 |
MySQL实例平均每秒钟的输入、输出流量,单位为KB |
|
QPS/TPS |
每秒钟SQL语句执行次数和事务处理数 |
|
InnoDB缓存读命中率、使用率、脏块率 |
InnoDB缓冲池的读命中率、使用率以及缓冲池脏块的百分率 |
|
InnoDB读写量 |
InnoDB平均每秒读取和写入的数据量 |
|
InnoDB读写次数 |
InnoDB每秒钟的读取和写入的次数 |
|
InnoDB日志 |
InnoDB的日志写入情况 |
|
MySQL执行语句时在硬盘上自动创建的临时表的数量 |
执行语句时在硬盘上自动创建的临时表的数量 |
|
MyISAM Key Buffer |
MyISAM平均每秒的Key Buffer使用状况 |
|
MyISAM读写次数 |
MyISAM平均每秒的读写次数 |
|
MySQL_COMDML |
数据库每秒SQL语句执行次数,包括的类型如下:Insert、Delete、Insert_Select、Replace、Replace_Select、Select、Update |
|
MySQL_RowDML |
InnoDB每秒钟操作执行次数,包括:
|
- 慢日志
- SQL洞察
- 数据库自治服务
因为上面已经有路径或帮助文档,这里不再赘述。在实际业务场景中情况可能会比上面提到的情况复杂的多,有可能是多种情况的叠加,不过排查问题的思路是一致的,希望上述方法对您有帮助。