前言
前两年我在银行工作的时候,接触到更多的是Oracle数据库,毕竟银行不差钱而且在这些系统建设的时候MySQL还不像现在这样被关注,现在有些银行也在开始在一些非重要系统上开始尝试去O了。而互金行业由于其互联网的属性,在数据库的选择上自然会考虑到去IOE(其实MySQL也是Oracle公司的)。我也是在这时开始对MySQL进行深入的学习。由于工作原因,我经常面试一些开发人员。也会经常问SQL优化的问题,我得到的答案大多数都会回答建索引,这时我会继续问如何建索引,又如何知道一个应用系统中众多SQL语句哪个有问题,有些基础好的会回答通过开启慢查询日志监控运行时间或IO不满足要求的SQL语句,这里暂不讨论MySQL的慢查询日志也不讨论索引的优化,先看看如何通过对SQL的执行计划的分析,发现SQL语句的性能问题。
查看SQL执行计划
在MySQL中查看SQL语句的执行计划是很容易的,只需要在SQL语句前面加上explain关键字,比如:
EXPLAIN SELECT * FROM tb_item_desc WHERE item_id IN (SELECT id FROM tb_item);
这是我样例数据库中对内容表的一个简单的查询,执行这条语句有,执行计划是如下图:
下面我们就以这个执行计划为例介绍一下执行计划中各个字段的含义
1.id
这个字段表示的是SQL语句的执行顺序,因为这个SQL语句中包含了子查询,所以执行计划中有两条记录,在这两条记录中id都是1,这就表明SQL语句的执行顺序是从上向下顺序执行的,如果用到了联合查询,id值可能不同,这时SQL语句的执行顺序以id值从大向小执行。
2.select_type
这个字段表示的是选择类型,这里选择的是SIMPLE。
3.table
这个字段顾名思义,就是本次查询用到了那些表。
4.type
这个字段比较重要,对SQL的优化有指导意义,该值代表的是我们的SQL使用了那种访问类型,通过它可以知道是否使用了索引,使用了哪种类型的索引,type有以下几种情况
ALL(全表扫描);
index(索引扫描);
range(范围扫描);
ref(非唯一索引扫描);
eq_ref(唯一索引扫描);
const(常数引用)。
这几种访问类型的查询效率是由慢到快的,因此我们在SQL语句的编写时要尽量避免使用全表扫描,尤其是对一些大表的扫描会对性能产生很大的影响,即使是单表查询也会很慢。
5.possible_keys
该值表示可能用到的索引,注意是可能,而不是实际使用的索引。有时候这个值不为空,但是依旧没有使用索引。
6.key
该值表示的是实际使用的索引的名字,如果是主键索引就是PRIMARY,或者是自建索引的名字。
7.key_len
索引使用的字节长度
8.ref
该值表示的是表连接匹配条件,如果用到了索引就是索引的名字,如果是全表扫描就是null。在上面的例子中,子查询就是个全表扫描,索引ref值是null。
9.rows
表示扫描行数,扫描的行数越小,表明效率就越高,这个值在SQL优化中也很有借鉴意义,通过优化索引,修改表关联关系等各种方法来降低这个值。
10.extra
这个值非常重要,也是SQL优化时必须看的一个值,它表示的是我们的SQL语句的真实执行情况,上面我们的SQL语句的子查询中改值为:using index。改值常见的还有using where,using temporary,using filesort。我们在SQL查询语句中尽量使用索引,减少临时表和文件排序的使用,因为这对IO效率有影响。
总结:
以上这些,就是我们在分析一条SQL语句的执行计划时,需要掌握的基本信息。通过这些信息可以让我们了解应用中SQL语句的执行情况,从而有助于对SQL语句的优化。千万别小看了SQL优化,可能一个简单的SQL优化能使程序性能成倍提高。另外还要说的一点是,在一些高并发,大访问量的应用系统中,尽量设计成单表查询,可能会违反数据库设计范式,造成数据冗余,但在互联网行业中,性能的提升可能往往比存储空间的浪费更重要。