对SQL慢查询的优化(MySQL)
一、慢查询原因
要对慢查询进行优化,首先要搞清楚慢查询的原因,原因主要有三:
(1)加载了不需要的数据列
(2)查询条件没有命中索引
(3)数据量太大
二、优化方案
优化也是针对这三个方向的:
在分析该语句时,请检查是否有超出需求的数据加载。这可能包括不必要的行数据被查询并舍弃。此外,在结果集合中可能存在过多的字段被加载进来。若发现上述问题,则需对该语句进行重新审视和重构。
(2)研究语句运行过程以获取相关索引信息随后对相应的语句或索引进行调整从而提高命中率
(3)如果无法进一步优化代码逻辑,请考虑是否存在由于数据规模过大导致的查询延迟问题;如果是的话,则建议将数据按照维度进行横向或纵向划分存储
三、补充-执行计划
1、MySQL的执行计划怎么看
(1)最简单的做法是,使用可视化工具Navicat,执行查询时打开【解释】

(2)具体的含义

| 执行计划字段对照表 | ||
|---|---|---|
| 序号 | 字段 | 作用 |
| 1 | id | id是一个有顺序的编号,是查询的顺序号 (1)id的顺序按select出现的顺序增长,有几个select就显示几行,就有几个id。 (2)id列的值越大执行的优先级越高越先执行,id列的值相同则从上往下执行,id列的值为NULL最后执行 |
| 2 | select_type | 表示查询中每个select子句的类型 (1)SIMPLE:定义为不包含UNION查询或子查询的查询类型
(2)PRIMARY:指定作为最外层查询(包含嵌套子查询)
(3)SUBQUERY:定义为子查询中最先出现的选择项
(4)UNION:指UNION操作中的后续执行部分
(5)DEPENDENT UNION:指UNION操作中的后续执行部分,在外部query结果依赖下执行
(6)UNION RESULT:指UNION操作产生的结果集合
(7)DEPENDENT SUBQUERY:指子query中最先出现的选择项,在外部query结果依赖下执行
(8)DERIVED:定义为由外层query引出的导出表选择项(通过FROM子句描述的子表选择项) |
| 3 | table | 表示该语句所涉及的目标表 |
|---|
| 5| type| 是优化SQL的重要字段,判断SQL性能和优化程度的重要指标。 type的取值类型范围: (1)const:通过索引一次命中,匹配一行数据 (2)system:表中只有一行记录,相当于系统表 (3)eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配 (4)ref:非唯一性索引扫描,返回匹配某个值的所有 (5)range:只检索给定范围的行,使用一个索引来选择行,一般用于:between,<,> (6)index:只遍历索引树 (7)ALL:表示全表扫描,这个类型的查询是性能最差的查询之一。随着表的数量增多,执行效率变慢 *(8)执行效率:
ALL < index < range< ref < eq_ref < const < system。最好是避免ALL和index |
| 6 | possible_keys | 表示Mysql在执行该sql语句的时候,可能用到的索引信息,仅仅是可能,实际不一会用到。很多时候索引不一定会命中。 |
|---|---|---|
| 8 | key_len | 表示查询优化器使用了索引的字节数,这个字段可以评估组合索引是否完全被使用,这也是我们优化sql时,评估索引的重要指标。 |
| 9 | ref | |
| 10 | rows | mysql 查询优化器根据统计信息,估算该sql返回结果集需要扫描读取的行数,这个值相关重要,索引优化之后,扫描读取的行数越多,说明索引设置不对,或者字段传入的类型之类的问题,说明要优化空间越大 |
| 11 | filtered | 返回结果的行占需要读到的行(rows列的值)的百分比,就是百分比越高,说明需要查询到数据越准确, 百分比越小,说明查询到的数据量大,而结果集 |
(1)采用外部排序功能:MySQL通过外部排序机制对结果集进行处理操作,并无法仅凭索引顺序实现排序效果。通常情况下,在需要执行外部排序的情况下建议避免使用这种方法的调用方式,默认情况下这种操作可能会导致CPU资源消耗增加以及延迟变长。
(2)采用基于索引的扫描方式:当SQL语句中包含Index关键字并完成Index树搜索后即可找到所需数据来源,默认情况下这种操作通常意味着数据库性能表现较为理想。
(3)若查询过程中调用了临时表功能:该情况通常出现在需要执行排序、分组或者多表连接的操作场景下,默认情况下这种操作可能导致查询执行效率降低并建议采取相应的优化措施。
(4)当SQL语句中包含WHERE子句时:该条件会直接影响数据匹配的过程,默认情况下这种过滤操作通常会带来较高的执行效率。
对1的一个例子:有多少个select就有多少行,就有多少id

注:执行计划就是SQL的执行查询的顺序。
2、SQL语句的执行顺序
在数据库系统中,SQL语句在执行过程中所遵循的顺序与传统的非关系型数据库相比具有显著的不同之处。
但是一般说的SQL语句的执行顺序是指:
Select * FROM student 这样的SELECT语句的执行顺序是先从...然后才是SELECT。
如果有where等其他关键字:
select 语句的执行顺序
| 1 | from |
|---|---|
| 2 | join |
| 3 | on |
| 4 | where |
| 5 | group by |
| 6 | count、sum等统计函数 |
| 7 | having |
| 8 | select |
| 9 | distinct |
| 10 | order by |
| 11 | limit |
3、关于索引没有命中的一种猜想
如果建立了索引尤其是复合索引之后仍然未能找到相应的数据项那么首先需要关注的是所建立的这些索引是否遵循最左前缀原则。
(1)左侧前缀策略:名称直接体现其核心特征的是左侧端点位置,在起始位置位于左侧端点处时能够实现所有相邻的索引都被识别出来
1)如果第一个字段是范围查询需要单独建一个索引;
当执行多列索引创建操作时,在where子 clause中应将出现频率最高的那一列置于左侧位置
当生成(a,b,c)复合索引时,在确保索引生效的前提下,则需遵循以下几种实现方式:直接引用字段名a、字段组合ab以及字段组合ac,并进一步构建出abc的形式。
(2)一个例子:
为student表创建一个组合索引 age_name_sex_index

在执行计划中可以看到,索引命中了,这时where 了 age字段

但是如果没有where了age字段,那么索引就不会命中

