MySQL索引优化案例

2019-03-20  本文已影响0人  云爬虫技术研究笔记

开发同学或多或少会遇到系统响应慢的问题,除了业务系统本身的问题外,常常会遇到SQL查询慢的问题,这篇文章结合实际案例分析MySQL InnoDB存储引擎的索引优化,这篇文章不会介绍B+树的知识点,如果需要了解聚集索引和辅助索引特点的同学可以参考这篇文章,这篇文章主要会介绍三星索引ICP优化.

如何分析SQL性能

首先是查看MySQL的状态,系统是否正常,常用的几个命令如下:

#显示状态信息(扩展show status like ‘XXX’)
Mysql> show status;
#显示系统变量(扩展show variables like ‘XXX’)
Mysql> show variables\G;
#显示InnoDB存储引擎的状态
Mysql> show engine innodb status\G;
#查看当前SQL执行,包括执行状态、是否锁表等
Mysql> show processlist ;

第二步是找出系统有哪些慢查询SQL,这个要通过slowLog来查询,首先开启慢查询日志,然后在对应日志路径找到mysql-slow.log,相关命令如下所示:

# 检查是否开启慢查询日志
show variables like '%slow%';
# 如果没有开启,也可以在运行时动态开启这个参数
set global slow_query_log=ON;
# 设置慢查询记录查询耗时多长的SQL,这里设置成100毫秒
set long_query_time = 0.1;
# 这里休眠500毫秒试一下慢查询日志是否会记录
select sleep(0.5)

找到了慢SQL后比较常见的做法就是用explain命令分析SQL执行计划,查看SQL语句是否命中了索引,explain的用法可以参考MySQL 性能优化神器 Explain 使用分析,在优化过程中我们可能需要看到优化前后的查询时间对比,这时候可以打开profiling开关,查看某条SQL语句的执行耗时情况,分析是哪个步骤耗时较长,相关设置如下:

# 查看是否开启profiling
select @@profiling;
# 开profiling,注意测试完关闭该特性,否则耗费资源
set profiling=1;
# 查看所有记录profile的SQL
show profiles;
# 查看指定ID的SQL的详情
show profile for query 1;
# 测试完,关闭该特性
set profiling=0;

一个profiling例子:


profiling

三星索引优化策略

三星索引的策略是根据查询语句来建立联合索引,比如有这样一条SQL,SELECT GroupId,AddTime,Status from Order WHERE GroupId = 10010 ORDER BY AddTime,如何用三星索引来优化这条查询呢?

ICP技术介绍

前面的章节多次提到了ICP技术,那到底什么是ICP呢,在介绍ICP之前我们先来看一下SQL语句的where条件提取规则:所有SQL的where条件,都可以归纳为3大类:Index KeyIndex Filter和Table Filter,下面的介绍以CREATE TABLE Order (GroupId int(11) DEFAULT NULL, AddTime datetime DEFAULT NULL, Status int(11) DEFAULT NULL,KEY IX_GroupId (GroupId), KEY IX_AddTime (AddTime)) ENGINE=InnoDB这个表结构为例,假设我们分别单独建立了groupIdAddTime的索引,假设我们要执行这样一条SQLselect groupid,addtime,status from Order where groupid < 10010 and addTime > '1970' and status = 0;,那SQL执行计划会是怎样呢?

Index Key

Index Key只是用来定位索引的起止范围,因此只在索引第一次搜索时使用,一次判断即可;

从起始范围之后读到的每一条索引记录,均需要判断是否在Index Key的范围内,以上面的SQL为例,Index Key就是GroupId,它的范围是GroupId < 10010.

Index Filter

用于过滤索引查询范围中不满足查询条件的记录,因此对于索引范围中的每一条记录,均需要与Index Filter进行对比,若不满足Index Filter则直接丢弃,继续读取索引下一条记录,在前面的SQL中,Index Filter就是AddTime > '1970',MySQL会把这个过滤条件下推到存储引擎层,ICP就是Index Condition Push Down,不管是Index Key还是Index Filter对应的列必须添加了索引.

Table Filter

Table FilterWhere条件最后一道防线,用于过滤通过前面索引的层层考验的记录,此时的记录已经满足了Index Key的范围,并且符合Index Filter的条件,存储引擎通过回表读取了完整的记录,判断整条记录是否满足Table Filter中的查询条件,同样的,若不满足,跳过当前记录,继续读取索引的下一条记录,若满足,则返回记录,此记录满足了where的所有条件,可以返回给前端用户.还是回到前面那条SQL,Where条件中的Status=0就是Table Filter,因为Status列并没有添加索引,所以只能通过回表读取该字段来过滤.

我们来总结下ICP的过程,MySQLIndex Filter条件AddTime>'1970'下推到存储引擎,存储引擎根据AddTime索引来过滤掉不符合where条件AddTime>'1970'的记录,然后把最终数据返回给MySQL Server,MySQL Server再根据where条件status=0来做最后的过滤,最后把数据返回给用户,这个过程减少了二次回表的次数,有效减少了磁盘IO.最后我们来看下explain语句的结果:

Table Filter

其他优化建议

上一篇下一篇

猜你喜欢

热点阅读