在过去的工作中,如何在各个环境中(开发、测试、生产)快速准确的发现应用的慢sql,并进行高效的推动,是一个很大的挑战。以下是一些经验
慢sql的定义
我们将执行时间超过1秒的sql都定义为慢sql。同时会导致
- 系统的响应时间延迟,影响用户体验
- 资源占用增加,增高了系统的负载,其他请求响应时间也可能会收到影响。
- 慢SQL占用数据库连接的时间长,如果有大量慢SQL查询同时执行,可能会导致数据库连接池的连接被全部占用,导致数据连接池打满、缓冲区溢出等问题,使数据库无法响应其他请求。
- 还有可能造成锁竞争增加、数据不一致等问题
因此,需要及时发现和优先慢sql,对系统稳定性是非常重要的
慢sql常见原因
- 缺乏索引/索引未生效,导致数据库全表扫描,会产生大量的IO消耗,产生慢SQL。
- 单表数据量太大,会导致加索引的效果不够明显。
- SQL语句书写不当,例如join或者子查询过多、in元素过多、limit深分页问题、order by导致文件排序、group by使用临时表等。
- 数据库在刷“脏页”,redo log写满了,导致所有系统更新被堵住,无法写入了。
- 执行SQL的时候,遇到表锁或者行锁,只能等待锁被释放,导致了慢SQL。
如何发现慢sql
- 数据库开启慢sql日志:数据库会将执行时间超过一定阈值的sql记录到日志中
- 链路追踪:通过慢接口以及代码,定位慢sql
- 开发过程中,进行代码review。通过对sql语句分析,发现索引使用不当、造成全表扫描、sql扫描行数过多、出现文件排序等。强制其修改后再提交
- 对数据库进行监控,重点对cpu使用情况、会话数,发现异常及时告警同时安排值班同时定位问题,尽量在第一时间解决数据库风险。同事建立问题跟踪,若因业务影响则指定负责人推进。
制定sql规范
- **【强制】**不允许使用select *
- **【强制】**不要使用count(列名)或count(常量)来替代count(),count()就是SQL92定义的标准统计行数的语法,跟数据库无关,跟NULL和非NULL无关。
- **【强制】**count(distinct col) 计算该列除NULL之外的不重复数量。注意 count(distinct col1, col2) 如果其中一列全为NULL,那么即使另一列有不同的值,也返回为0。
- **【强制】**若列会执行计算,则强制其使用默认值不允许为NULL,当某一列的值全是NULL时,count(col)的返回结果为0,但sum(col)的返回结果为NULL,因此使用sum()时需注意NPE问题。
- **【强制】**使用ISNULL()来判断是否为NULL值。
- **【强制】**对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或表名)进行限定。
- **【强制】**在代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
- **【强制】**不得使用外键与级联,一切外键概念必须在应用层解决。
执行计划相关解释
通过explain语句可以提供关于SQL查询执行的详细信息和执行计划,并且可以了解sql的索引使用情况以及数据访问方式。通过使用Explain语句,可以了解SQL是如何执行的,并且可以看出其可能存在的性能问题。
字段 | 解析 |
---|---|
id | 查询的每个操作的唯一标识符,无特殊含义 |
select type | 查询操作的类型,常见的包括SIMPLE(简单查询)、PRIMARY(主键查询)、SUBQUERY(子查询)、DERIVED(派生表查询)等 |
table | 表示查询操作设计的表名 |
partitions | 表示查询操作涉及的分区信息 |
type | 表示查询操作的连接类型或访问类型,常见的包括ALL(全表扫描)、index(索引扫描)、range(范围扫描)、ref(基于索引的引用)、eq_ref(唯一索引使用)、const(常数表)、system(系统表)等 |
possible_keys | 表示查询可能使用的索引 |
key | 表示查询操作实际使用的索引 |
key_len | 表示索引使用的字节数 |
ref | 表示查询操作使用的索引之间的引用关系 |
rows | 执行查询操作时,mysql认为必须要去检查和判断的记录条数 |
filtered | 表示符合查询条件的数据百分比 |
Extra | 表示额外的信息和备注,如“Using where”表示使用了WHERE子句过滤,“Usingindex“表示只使用了索引而没有访问表等。 |
需要重点关注几个特别的情况,出现以下几点都可能造成sql性能的降低。
- 使用全表扫描,性能最差,即type=“ALL”
- 扫描行数过多,即rows>阈值,阈值一般为10w
- 查询时使用了排序操作,也比较耗时,即Extra包含"Using filesort”
- 索引类型为index,代表全盘扫描了索引的数据,Extra信息为Using where,代表要搜索的列没有被索引覆盖,需要回表,性能较差。
规范
- 主键不允许使用uuid,小表可以使用自助主键,大表的主键必须使用递增的id组件
- 尽量保证核心sql查询的,where、order by、group by 都可以用上索引。建立联合索引,尽量让区分度大的在索引左边,经常做范围查询的字段放在最后一个
- 索引原则上不应该超过3个。尽量利用1到2个多字段联合索引,抗下80%以上的查询。然后在剩下20%场景,建立一个联合索引。保证99%以上的查询都能充分利用索引
慢sql治理流程
- 高危慢sql,建立任务持续跟踪,每个版本汇报直到问题解决。并指定处理优先级,不同的优先级可以容忍的时间不同,若超过容忍时间,则影响团队评价。
- 针对重点业务或慢sql高发团队,安排有经验的同事协助推进。
- 新功能开发过程中,根据实际情况,及时处理或排期处理。必须在排期时间内完成改造,超期则影响团队评价
总结
慢sql可能引起很严重的系统性能问题,影响系统的可用性和稳定性。需要及时发现和治理。因此,我们建立了一套发现-分析-治理的流程,极大的减少了因慢sql引起的系统性能问题