mysql sql调优


个人感觉mysql的执行优化器和oracle比还是有很大的差距,oracle的很智能,好了,既然使用了mysql就不说这些的了。
要分析sql必然少不了执行计划,只有搞清楚执行激活每个标识的意思,各个子查询的执行顺序,才能做出好的优化

一:mysql执行计划详解

Explain语法
EXPLAIN SELECT ……
变体:

  1. EXPLAIN EXTENDED SELECT ……
    将执行计划“反编译”成SELECT语句,运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句
  2. EXPLAIN PARTITIONS SELECT ……
    用于分区表的EXPLAIN
    执行计划包含的信息
    在这里插入图片描述
    id
    包含一组数字,表示查询中执行select子句或操作表的顺序在这里插入图片描述
    id相同,执行顺序由上至下在这里插入图片描述
    如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行 在这里插入图片描述
    id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行

select_type
表示查询中每个select子句的类型(简单 OR复杂)
在这里插入图片描述

a.SIMPLE:查询中不包含子查询或者UNION
b.查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
c.在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
d.在FROM列表中包含的子查询被标记为:DERIVED(衍生)
e.若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在 FROM子句的子查询中,外层SELECT将被标记为:DERIVED
f.从UNION表获取结果的SELECT被标记为:UNION RESULT

type

表示MySQL在表中找到所需行的方式,又称“访问类型”,常见类型如下:
在这里插入图片描述
由左至右,由最差到最好

a.ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

在这里插入图片描述

b.index:Full Index Scan,index与ALL区别为index类型只遍历索引树
在这里插入图片描述
c.range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
在这里插入图片描述
range访问类型的不同形式的索引访问性能差异
在这里插入图片描述
d.ref:非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找
在这里插入图片描述
在这里插入图片描述

e.eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
在这里插入图片描述

f.const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量
在这里插入图片描述
system是const类型的特例,当查询的表只有一行的情况下, 使用system
g.NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引
在这里插入图片描述
possible_keys

指出MySQL能使用哪个索引在表中找到行,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

key
显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL
TIPS:查询中若使用了覆盖索引,则该索引仅出现在key列表中
在这里插入图片描述

key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度

在这里插入图片描述
在这里插入图片描述
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的

ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

在这里插入图片描述
本例中,由key_len可知t1表的idx_col1_col2被充分使用,col1匹配t2表的col1,col2匹配了一个常量,即 ’ac’

rows
表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数

在这里插入图片描述
Extra
包含不适合在其他列中显示但十分重要的额外信息

a.Using index

该值表示相应的select操作中使用了覆盖索引(Covering Index)
在这里插入图片描述
TIPS:覆盖索引(Covering Index)
MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件
包含所有满足查询需要的数据的索引称为 覆盖索引(Covering Index)

注意:
如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降

b.Using where

表示MySQL服务器在存储引擎受到记录后进行“后过滤”(Post-filter),
如果查询未能使用索引,Using where的作用只是提醒我们MySQL将用where子句来过滤结果集

在这里插入图片描述
c.Using temporary

表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询

在这里插入图片描述

d.Using filesort

MySQL中无法利用索引完成的排序操作称为“文件排序”

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

MySQL执行计划的局限

•EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
•EXPLAIN不考虑各种Cache
•EXPLAIN不能显示MySQL在执行查询时所作的优化工作
•部分统计信息是估算的,并非精确值
•EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划

二:mysql中常见的hint

如果可以通过改写sql来实现,则优先改写sql,不要随意使用hint,一定要严格测试,使用hint后不一定比之前快,不要想当然
有时写的sql,通过查看执行计划,发现没有按照最优的路线走,并且执行缓慢,则可以通过hint提示来调优
对于经常使用oracle的朋友可能知道,oracle的hint功能种类很多,对于优化sql语句提供了很多方法。同样,在mysql里,也有类似的hint功能。下面介绍一些常用的。
强制索引 FORCE INDEX
SELECT * FROM TABLE1 FORCE INDEX (INDEX2) …
以上的SQL语句只使用INDEX2索引。
忽略索引 IGNORE INDEX
SELECT * FROM TABLE1 IGNORE INDEX (FIELD1, FIELD2) …
在上面的SQL语句中,TABLE1表中FIELD1和FIELD2上的索引不被使用。
关闭查询缓冲 SQL_NO_CACHE
SELECT SQL_NO_CACHE field1, field2 FROM TABLE1;
有一些SQL语句需要实时地查询数据,或者并不经常使用(可能一天就执行一两次),这样就需要把缓冲关了,不管这条SQL语句是否被执行过,服务器都不会在缓冲区中查找,每次都会执行它。
强制查询缓冲 SQL_CACHE
SELECT SQL_CALHE * FROM TABLE1;
如果在my.ini中的query_cache_type设成2,这样只有在使用了SQL_CACHE后,才使用查询缓冲。

优先操作 HIGH_PRIORITY
HIGH_PRIORITY可以使用在select和insert操作中,让MYSQL知道,这个操作优先进行。
SELECT HIGH_PRIORITY * FROM TABLE1;
滞后操作 LOW_PRIORITY
LOW_PRIORITY可以使用在insert和update操作中,让mysql知道,这个操作滞后。
update LOW_PRIORITY table1 set field1= where field1= …
延时插入 INSERT DELAYED
INSERT DELAYED INTO table1 set field1= …
INSERT DELAYED INTO,是客户端提交数据给MySQL,MySQL返回OK状态给客户端。而这时并不是已经将数据插入表,而是存储在内存里面等待排队。当mysql有空余时,再插入。另一个重要的好处是,来自许多客户端的插入被集中在一起,并被编写入一个块。这比执行许多独立的插入要快很多。坏处是,不能返回自动递增的ID,以及系统崩溃时,MySQL还没有来得及插入数据的话,这些数据将会丢失。

强制连接顺序 STRAIGHT_JOIN
SELECT TABLE1.FIELD1, TABLE2.FIELD2 FROM TABLE1 STRAIGHT_JOIN TABLE2 WHERE …
由上面的SQL语句可知,通过STRAIGHT_JOIN强迫MySQL按TABLE1、TABLE2的顺序连接表。如果你认为按自己的顺序比MySQL推荐的顺序进行连接的效率高的话,就可以通过STRAIGHT_JOIN来确定连接顺序。
STRAIGHT_JOIN只适用于inner join,并不适用于left join,right join,因为left join,right join已经代表指定了表的执行顺序

强制使用临时表 SQL_BUFFER_RESULT
SELECT SQL_BUFFER_RESULT * FROM TABLE1 WHERE …
当我们查询的结果集中的数据比较多时,可以通过SQL_BUFFER_RESULT.选项强制将结果集放到临时表中,这样就可以很快地释放MySQL的表锁(这样其它的SQL语句就可以对这些记录进行查询了),并且可以长时间地为客户端提供大记录集。
分组使用临时表 SQL_BIG_RESULT和SQL_SMALL_RESULT
SELECT SQL_BUFFER_RESULT FIELD1, COUNT(*) FROM TABLE1 GROUP BY FIELD1;
一般用于分组或DISTINCT关键字,这个选项通知MySQL,如果有必要,就将查询结果放到临时表中,甚至在临时表中进行排序。SQL_SMALL_RESULT比起SQL_BIG_RESULT差不多,很少使用。

三:优化例子

1.连接顺序调整,及强制使用索引

1)如下,tb1,大表,不应该被作为开始表,tb4分页子查询,最多只有15条数据,应该被作为开始表,优化前执行时间0.341秒
在这里插入图片描述
2)使用STRAIGHT_JOIN做如下优化,优化后执行时间0.224秒,感觉优化力度不大,有可能是tb1的数据量还不够大
在这里插入图片描述
3)第二步优化后发现连接tb1的时候还是走的全表扫描,没有使用上主键索引,这里强制使用主键索引FORCE INDEX (primary) ,优化后执行时间0.024
在这里插入图片描述

参考文档
https://www.cnblogs.com/ggjucheng/archive/2012/11/11/2765237.html
https://www.cnblogs.com/jpfss/p/11490765.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值