【MySQL】sql调优实战教学

本文介绍了如何定位和优化MySQL中的慢查询SQL,包括开启慢查询日志,分析SQL性能,使用EXPLAIN工具,以及通过修改SQL或创建索引来提升查询效率。通过实例展示了如何分析SQL执行计划,理解不同查询类型和Extra信息,并讨论了查询优化器的选择策略。最后强调了根据具体场景测试和选择合适索引的重要性。
摘要由CSDN通过智能技术生成

如何定位并优化慢查询Sql?

具体场景具体分析只提出大致思路,其实这个问题属于开放性的题目,主要考察有没有做过SQL优化,由于该问题属于经验的问题,做过了就是做过了没做过就是没做过,问了你就知道是没有做过的,没办法给出大家准确的答案只能给出大致思路,这里提前公布一下答案。然后我们再依依去讲解

  1. 根据慢日志定位慢查询SQL

  2. 使用explain等工具分析SQL

  3. 修改SQL或者尽量让SQL走索引

1)根据慢日志定位慢查询SQL

那开始我们的第一步,定位并优化慢SQL。首先我们先要分析慢日志,接下来我们将通过一个简单实用的调优例子,来看看这个问题。我们再次打开MySql客户端,连接上我们的database_demo这个数据库,那myql里很多自带的系统变量,咱们可以通过查看一些系统变量来得知我们的配置信息,那这里呢,我们是要查询跟慢日志有关的配置信息。什么是慢日志呢,慢日志就是用来记录我们查询得比较慢得一些SQL。

那我们来查询一些变量。

show variables like '%quer%';

在这里插入图片描述

那这些变量呢,我们只需要关注这3个。

第一个是slow_query_log 顾名思义就是我们得慢日志了,它现在是 OFF 也就是是关闭的,我们需要将它打开。

第二个是slow_query_log_flie 这个文件会记录我们的慢日志。(慢日志路径)

第三个是long_query_time 现在表示得是每次执行sql花费10秒钟的话。就会被记录到 slow_query_log_flie 对应的文件中。

了解完这三个变量之后呢我们还需要对它进行设置,slow_query_log 我们是要将它进行打开的,并且呢long_query_time 它现在是10 秒钟对于我们的程序运行来说是非常非常慢的。因此通常情况下它执行超过1秒钟我们就认为这条sql是比较慢的了,要去做优化了,因此这里我们呢把 long_query_time 设置成 1秒。

set global slow_query_log = on; # 打开慢查询  立即设置立即生效

set global long_query_time = 1; # 设置慢查询时间 单位 s (秒)  重新连接MySql客户端才能生效

# 如果想让 配置立即生效linux 可以在 my.cnf,windows是my.ini 配置文件,对这些值进行设置,一旦设置是永久# 保存的。如果我们仅在这里做set global 当我们重启数据库服务的时候,他就会还原成之前的状态,也就是说 
# slow_query_log 是 OFF 它就是 OFF

那我们现在重新连接一下数据库。

在这里插入图片描述

可以看到之前的 set global 设置已经成功了。

我们了解了变量,我们还需要了解一些系统的状态有个指令

show status like '%slow_queries%';

我们执行一下可以看到,我们慢查询的数量

在这里插入图片描述

现在我们开始来制造一些慢查询,之前我已经在person_info_large 这个数据库灌入了两百万条数据。

select count(*) from person_info_large;

在这里插入图片描述

接下来我们先来制造一些慢查询,我们先来看看这个person_info_large 的结构(area、title是组合索引)

在这里插入图片描述

发现他有一个name的字段。

通过name 来组织一个SQL出来

select name from person_info_large order by name desc;

在这里插入图片描述

由于数据比较多,所以执行了4.271s 不过这里不是准的。

我们再来看一下,慢查询日志记录已经有数据了。

在这里插入图片描述

然后再具体查看下日志。因为我是在部署在docker容器中的,所以需要先进入到容器中

docker exec -it mysql /bin/bash

查看日志信息

# 日志比较大的话使用tail -f 500 /var/lib/mysql/xxxxxx-slow.log
vim /var/lib/mysql/baidudeMacBook-Pro-slow.log	

在这里插入图片描述

我们发现刚才我们的那条数据已经被记录到慢日志里面了。这里的Query_time : 4.96521s 才是我们的真正查询时间,刚才我们客户端显示的是 4.271s 那是不正确的,实际以这个为准。

到这里我们可以通过慢日志去捕获一些慢SQL,进而呢去分析这个SQL为什么那么慢,然后再对它进行调优

使用explain等工具分析SQL

在分析和查询性能的时候,explain会非常管用,这个关键字呢一般会房子select 查询语句前面,用于描述MySql如何进行查询操作,以及MySql成功返回结果集需要执行的函数。explain可以帮我们分析select查询语句,让我们知道查询效率低下的原因,从而改进我们的查询。让查询优化器更好的工作。那explain是怎么用的呢?非常简单像这里我们分析一下刚才的查询为什么这么慢。

# 格式: explain XXX(查询语句)
explain select name from person_info_large order by name desc;

我们可以得到分析结果

在这里插入图片描述

这里执行的非常快,那也就是说执行的时候,该SQL呢并没有真正的去运行。而是对它做了一些分析。我们可以看出 explain 的结果由多列组成,其中有两列对调优SQL非常的重要,就是 type 和 Extra 。

先上一个官方文档表格的中文版:

Column含义
id查询序号
select_type查询类型
table表名
partitions分区
typejoin类型
prossible_keys可能会选择的索引
key实际选择的的索引
key_len索引的长度
ref与索引作比较的列
rows要检索的行数(估算值)
filtered查询条件过滤的行数的百分比
Extra额外信息

首先需要注意:MYSQL 5.6.3以前只能EXPLAIN SELECT; MYSQL5.6.3以后就可以EXPLAIN SELECT,UPDATE,DELETE

详细含义请参考博文:explain有哪些字段,分别有什么含义?

type

咱们先来讲讲type,type 表示MySql找到需要数据行的方式,如下。方式有很多,咱们不需要一一记忆,它们的性能从最优到最差:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

其中index和All 表明本次查询走的是全表扫描。因此当我们看到查询语句是慢查询语句 type 是这两个值中的一个的时候,证明语句是需要优化了的。使用索引至少要达到range级别。

Extra

咱们再来讲讲Extra 虽然他们有 type 那么直观。但我们可以从它们这里获得一些更为详细的信息。辅助我们了解一些语句的查询方式,它的类型也非常的多,这里呢我们只需要关注两种 即有可能优化的方式

extra 项说明
Using filesort表示MySQL会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。MySQL中无法利用索引完成的排序操作称为“文件排序”
Usimg temporary表示MySQL在对查询结果排序是使用临时表。常见于排序 order by 和分组查询 group by。

很明显我们的刚刚的分析结果 type 对应的 All ,Extra 对应的 using filesort 所以它们要走的是全表扫描,所以这个语句是非常慢了。所以我们就要对这条语句进行调优了。

修改SQL或者尽量让这条SQL走索引

咱们再回到这个语句里面看看怎么去优化它。第一,可以修改SQL,我们先看看它的构造。

在这里插入图片描述
我们可以看到name是没有走索引的,而account是有索引的,那我们可以用account来替代name,这样也是能满足业务上的需求的。既然account走的是索引,那咱们可以这么该

select name from person_info_large order by name desc; # 原sql

select account from person_info_large order by account desc; # 优化

在这里插入图片描述
我们看到他们的性能已经得到了提升,type 等于 index ,Extra 等于 using index 也就是他已经走了索引了。那走的索引是什么呢。我们可以看到这个key是account,它是唯一键索引这样我们就能让它的性能得到明显的提升了。

在这里插入图片描述

那有时候呢,靠改SQL时没办法满足我们的业务需求的那我们的业务呢,就是按照name 来排序。那怎么办呢。这时候,我们还有另外一个方案。就是加索引了。

alter table person_info_large add index idx_name(name);

这条语句执行的也挺慢,但是不会进入慢查询。因为这条SQL属于 DDL 也就是属于数据定义语言。它主要用来操纵我们的表结构的。而用来操纵数据的 对数据进行增删改查的 也就是我们的 DML 语言呢。才会进入到我们的慢查询log当中。

加了索引之后我们再执行

explain select name from person_info_large order by name desc;

在这里插入图片描述

我们就可以看到 type 走的时 index , key 走的时刚才我们刚刚定义的 idx_name ,Extra 走的是using index 也就是走了索引了,表示我们已经调优了相关语句。我们再次执行查询。

在这里插入图片描述

这是告诉大家如何调优SQL的一个方式,大家也可以依据大家实际的工作经验去做一个调整。

接下来来补充一个知识点,也就是问一下大家我们的

explain select count(id) from person_info_large;

这条语句会走哪个索引?它应该会走索引吧,不会傻到进行全表扫描吧。那我们也可以回想到之前的知识哦,B+树的叶子节点它是有链表的因此我们统计的时候呢,就直接走链表了,就方便我们做统计

在这里插入图片描述
有那么多个B+树它会选择哪个,他会选择密集索引还是选择我们的稀疏索引呢?有的同学可能会说它肯定会走主键啊,走我们的密集索引更快啦,毕竟它的数据也在里面嘛,那我们可以试着跑一下。

在这里插入图片描述

结果出乎我们的意料啊,type = index 是预期的,但是key呢它却用的是account用的是我们的唯一键并不是用的我们的主键,然后Extra走的是索引了。为什么用的是account 而不是用的是我们的id呢,id才是它的主键啊,大家可能都有这样的疑问。之所以去走这个索引呢,是因为我们的这个查询优化器来做决定的。MySql的查询优化器是最重要的目标是尽可能地使用索引并且最严格地索引来消除尽可能多地数据行。最终目标是提交select 语句查找数据行,而不是排除数据行。优化器试图排除数据行地原因是它排除数据行的速度越快那么找到与条件匹配的数据行越快,因此查询优化器会根据它的一些分析和判断的标准决定走哪个索引,这里他没选择主键索引大致原因是由于密集索引的叶子节点把其它列的数据呢,也都存放到了叶子节点当中,在这里变成它的一个缺点了。这样查询的效率呢因为我们的数据都放在一起了,它的效率呢会比稀疏索引要低。因为毕竟稀疏索引只存储了关键字,即主键的值这样呢我们在内存里面就可以加载更多的关键字和主键的值去做 count 了。这样能够节约性能所以呢我们的查询优化器就选择它。不信我们可以直接强制的去走主键索引,然后我们对比一下两则的耗时。

我们来执行对比一下:

select count(id) from person_info_large;   # 执行时间 456 ms

select count(id) from person_info_large force index(primary); # 执行时间 633 ms

大家可以看到走primary key 未必比走其它索引要快。那MySQL查询优化器固然很厉害。但那只是个程序有时它按照其准则算出来的其索引,也不一定是最优的。还是要大家具体情况具体分析。根据一些特定场景的测试结果使用更适合的索引以使sql在改场景下最优。这时候呢我们就想到了这个force index ,使用force index 去测试各种索引去看看哪个索引是比较好的。

接下来我们来回顾一下这个如何调优sql的答案。

第一呢先根据慢日志,定位查询慢sql

第二使用explain 等工具分析该条sql

第三 修改sql或者尽量让该条sql走索引提升它的性能

推荐博客

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值