SQL优化 | 青训营笔记

110 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第4篇笔记。

0. 查询SQL语句执行频率

可使用show [session | global] status查看当前数据库状态信息。可判断当前数据库是以插入为主还是查询为主。

eg: show global status like ‘Com_______’ 查看全局状态信息

status

eg: show status like ‘Innodb_rows_%’ 查看Innodb表中状态信息

innodb

1. 定位低效率SQL语句

  • 慢查询日志:通过慢查询日志定位效率较低的SQL语句。

2. explain分析

explain

2.1 id

id表征着select子句或是操作表的顺序,一般来说有以下几种情况:

  • id相同表示加载表的顺序从上到下(连表查询)

id

  • id不同,id值大的优先被执行(子查询)

    id

  • id有相同的也有不同的,相同的是同一组,从上往下顺序查询,id值大的优先执行(一般也还是子查询)

2.2 select_type

常见的select_type结果

select_typeMeaning
SIMPLE简单的select单表查询
PRIMARY查询中包含子查询
SUBQUERY子查询
DERIVED在FROM列表中包含的子查询(查询结果作为临时表)
UNION若第二个SELECT出现在UNION后,则标记为UNION
UNIONRESULT从UNION表中获取结果的select

2.3 type

type指的是该查询的类型,是一个比较重要的指标,常见的结果为

typeMeaning
NULL不访问任何表和索引,直接返回结果
system表只有一行记录,一般不会出现
const通过索引一次找到,一般出现在主键或唯一索引,只匹配一行数据
eq_ref类似于ref,使用唯一索引,通过主键的关联查询出一行数据
ref非唯一索引扫描,返回匹配某个值的所有行
range检索给定返回的行,一般出现在between,< > in等
index遍历索引树,比all快
all遍历全表才找到匹配的行

2.4 key

与key相关的主要有三个字段:possible_keys 可能用到的索引,key 实际用到的索引,key_len索引使用的字节数(一般来说越短越好

2.5 extra

额外的信息,一般有以下结果:

extrameaning
using filesort使用外部的索引排序,而不是表内的索引排序,效率低
using temporary使用临时表保存中间结果,常见于order by,group by
using index使用了覆盖索引,避免访问表的数据行,效率高
using index condition使用了索引,但不是所有的列数据都在索引树上,访问了实际的数据行
using where使用where条件过滤数据
using join buffer进行了嵌套循环计算

3. show profile分析SQL

首先判断是否开启profile:select @@have_profiling,如果未开启,手动开启:set profiling = 1

通过profile,我们可以进一步的分析SQL语句中每一步的耗时:

profile

还可以进一步跟踪到每一个query:

query

4. 具体案例

4.1 插入大批量数据

对比InnoDB类型的表,有以下建议

  • 按主键顺序进行插入数据,减少索引树新增结点时间
  • 对于数据确定的表,可以关闭唯一性校验,提高导入效率。(SET UNIQUE_CHECKS = 0)
  • 手动提交事务

4.2 优化insert语句

  • 同时对一张表插入多行数据时应写在一个insert语句里,减少连接时间
  • 在事务中进行数据插入(数据量比较大分段提交)
  • 按主键顺序有序插入数据

4.3 优化order by语句

尽量使用有序索引扫描直接返回有序数据,将using filesort优化到using index级别。

Hint:排序的顺序需要和索引的顺序保持一致,否则也会导致using filesort

4.4 优化group by语句

group by实际上也会进行排序操作,相当于先排序再分组。如果想要避免排序结果的时间开销,我们可以使用order by null来禁止排序,优化掉了filesort。也可以对order by列创建索引,优化到Using index层面。

4.5 优化子查询

推荐使用多表联查来代替子查询。多表联查可以做到ref级别,优于子查询的index级别。