MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)


Posted in MySQL onApril 09, 2022

1.概述

在应用系统开发过程中,由于初期数据量小,开发人员写SQL语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多SQL语句开始逐渐显露出性能问题,对生产环境的影响也越来越大,此时这些有问题的SQL语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化,该章节将详细介绍在MySQL中优化SQL语句的方法。

2.通过show status命令了解各种SQL的执行频率

MySQL客户端连接成功后,通过show [session|global]status命令可以提供服务器状态信息,也可以在操作系统上使用mysqladmin extended-status命令获得这些消息。show [session|global] status可以根据需要加上参数“session”或者“global”来显示session级(当前连接)的统计结果和global级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。
下面的命令显示了当前session中所有统计参数的值:

-- 查看会话所有统计的值
SHOW STATUS LIKE 'Com_%';
Or
SHOW SESSION STATUS LIKE 'Com_%';

MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)

下面的命令显示了当前global中所有统计参数的值:
-- 查看全局所有统计的值

SHOW GLOBAL STATUS LIKE 'Com_%';

MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
Com_xxx表示每个xxx语句执行的次数,我们通常比较关心的是以下几个统计参数:
●Com_select:执行SELECT操作的次数,一次查询只累加1。
●Com_insert:执行INSERT操作的次数,对于批量插入的INSERT操作,只累加一次。
●Com_update:执行UPDATE操作的次数。
●Com_delete:执行DELETE操作的次数。
上面这些参数对于所有存储引擎的表操作都会进行累计。下面这几个参数只是针对InnoDB存储引擎的,累加的算法也略有不同。
●Innodb_rows_read:SELECT查询返回的行数。
●Innodb_rows_inserted:执行INSERT操作插入的行数。
●Innodb_rows_updated:执行UPDATE操作更新的行数。
●Innodb_rows_deleted:执行DELETE操作删除的行数。
通过以上几个参数,可以很容易地了解当前数据库的应用系统是以插入更新为主还是以查询操作为主,以及各种类型的SQL大致的执行比例是多少。对于更新操作的计数,是对执行次数的计数,不论提交还是回滚都会进行累加。
对于事务型的应用,通过Com_commit和Com_rollback可以了解事务提交和回滚的情况,对于回滚操作非常频繁的数据库,可能意味着应用编写存在问题。此外,以下几个参数便于用户了解数据库的基本情况。 
●Connections:试图连接MySQL服务器的次数。
●Uptime:服务器工作时间。
●Slow_queries:慢查询的次数。

3.定位执行效率较低的SQL语句

可以通过以下两种方式定位执行效率较低的SQL语句。
通过慢查询日志定位那些执行效率较低的SQL语句,用--log-slow-queries[=file_name]选项启动时,mysqld写一个包含所有执行时间超过long_query_time秒的SQL语句的日志文件。
慢查询日志在查询结束以后才纪录,所以在应用系统反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看SQL的执行情况,同时对一些锁表操作进行优化。

4.通过EXPLAIN分析低效SQL的执行计划

通过定位执行效率较低的SQL语句后,可以通过EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序,比如想统计所有库存阶梯数量,需要关联goods_stock表和goods_stock_price表,并且对goods_stock_price.Qty字段做求和(sum)操作,相应 SQL 的执行计划如下:

EXPLAIN SELECT SUM(sp.Qty)
FROM goods_stock AS s LEFT JOIN goods_stock_price AS sp
ON s.ID=sp.GoodsStockID;

MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)

如上图所示每个列的简单解释如下:

●select_type:表示 SELECT 的类型,常见的取值有:
  ◎SIMPLE(简单表,即不使用表连接 或者子查询)。
  ◎PRIMARY(主查询,即外层的查询)、UNION(UNION 中的第二个或 者后面的查询语句)、◎SUBQUERY(子查询中的第一个SELECT)等。
●table:输出结果集的表。
●type:表示表的连接类型,性能由好到差的连接类型为:
  ◎system(表中仅有一行,即常量表)。
  ◎const(单表中最多有一个匹配行,例如primary key或者unique index)。
  ◎eq_ref(对于前面的每一行,在此表中只查询一条记录,简单来说,就是多表连接中使用primary key或者unique index)。
  ◎ref(与eq_ref类似,区别在于不是使用primary key或者unique index,而是使用普通的索引)。
  ◎ref_or_null(与ref类似,区别在于条件中包含对NULL的查询)。
  ◎index_merge(索引合并优化)。
  ◎unique_subquery(in的后面是一个查询主键字段的子查询)。
  ◎index_subquery(与unique_subquery类似,区别在于in的后面是查询非唯一索引字段的子查询)。
  ◎range(单表中的范围查询)。
  ◎index(对于前面的每一行,都通过查询索引来得到数据)。
  ◎all(对于前面的每一行,都通过全表扫描来得到数据)。
●possible_keys:表示查询时,可能使用的索引。
●key:表示实际使用的索引。
●key_len:索引字段的长度。
●rows:扫描行的数量。
●filtered:返回结果的行占需要读到的行(rows列的值)的百分比。
●Extra:执行情况的说明和描述。
  ◎Using index(此值表示mysql将使用覆盖索引,以避免访问表)。
  ◎Using where(mysql 将在存储引擎检索行后再进行过滤,许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where子句的查询都会显示“Using where”。有时“Using where”的出现就是一个暗示:查询可受益于不同的索引)。
  ◎Using temporary(mysql 对查询结果排序时会使用临时表)。
  ◎Using filesort(mysql会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。mysql有两种文件排序算法,这两种排序方式都可以在内存或者磁盘上完成,explain不会告诉你mysql将使用哪一种文件排序,也不会告诉你排序会在内存里还是磁盘上完成)。
  ◎Range checked for each record(index map: N) (没有好用的索引,新的索引将在联接的每一行上重新估算,N是显示在possible_keys列中索引的位图,并且是冗余的)。

5.确定问题并采取相应的优化措施

经过以上定位步骤,我们基本就可以分析到问题出现的原因。此时我们可以根据情况采取相应的改进措施,进行优化提高语句执行效率。
在上面的例子中,已经可以确认是goods_stock是走主键索引的,但是对goods_stock_price子表的进行了全表扫描导致效率的不理想,那么应该对goods_stock_price表的GoodsStockID字段创建索引,具体命令如下:

-- 创建索引CREATE INDEX idx_stock_price_1 ON goods_stock_price (GoodsStockID);-- 附加删除跟查询索引语句ALTER TABLE goods_stock_price DROP INDEX idx_stock_price_1;SHOW INDEX FROM goods_stock_price;

创建索引后,我们再看一下这条语句的执行计划,具体如下:

EXPLAIN SELECT SUM(sp.Qty)
FROM goods_stock AS s LEFT JOIN goods_stock_price AS sp
ON s.ID=sp.GoodsStockID;

MySQL中优化SQL语句的方法(show status、explain分析服务器状态信息)
可以发现建立索引后对goods_stock_price子表需要扫描的行数明显减少(从 3 行减少到1行),可见索引的使用可以大大提高数据库的访问速度,尤其在表很庞大的时候这种优势更为明显。

参考文献:
深入浅出MySQL大全

MySQL 相关文章推荐
详解MySQL 联合查询优化机制
May 10 MySQL
MySQL 8.0 之不可见列的基本操作
May 20 MySQL
Mysql官方性能测试工具mysqlslap的使用简介
May 21 MySQL
修改MySQL的数据库引擎为INNODB的方法
May 26 MySQL
Mysql文件存储图文详解
Jun 01 MySQL
Navicat连接MySQL错误描述分析
Jun 02 MySQL
MySQL8.0的WITH查询详情
Aug 30 MySQL
MySQL创建定时任务
Jan 22 MySQL
MySQL派生表联表查询实战过程
Mar 20 MySQL
MySql重置root密码 --skip-grant-tables
Apr 11 MySQL
mysql 排序失效
May 20 MySQL
MySQL 原理优化之Group By的优化技巧
Aug 14 MySQL
进阶篇之linux环境下安装MySQL数据库
MySQL的存储函数与存储过程的区别解析
Apr 08 #MySQL
MySQL数据库查询进阶之多表查询详解
MySQL中一条SQL查询语句是如何执行的
解决MySQL Varchar 类型尾部空格的问题
Apr 06 #MySQL
mysql的单列多值存储实例详解
Apr 05 #MySQL
详细聊一聊mysql的树形结构存储以及查询
You might like
正义联盟的终局之战《天启星战争》将成为DC动画宇宙的最后一部
2020/04/09 欧美动漫
php中导出数据到excel时数字变为科学计数的解决方法
2013/02/03 PHP
Javascript写了一个清除“logo1_.exe”的杀毒工具(可扫描目录)
2007/02/09 Javascript
jQuery使用手册之一
2007/03/24 Javascript
javascript replace方法与正则表达式
2008/02/19 Javascript
JavaScript Cookie显示用户上次访问的时间和次数
2009/12/08 Javascript
javascript检测浏览器flash版本的实现代码
2011/12/06 Javascript
javascript实现可全选、反选及删除表格的方法
2015/05/15 Javascript
JavaScript实现列表分页功能特效
2015/05/15 Javascript
简介AngularJS的视图功能应用
2015/06/17 Javascript
数据结构中的各种排序方法小结(JS实现)
2016/07/23 Javascript
JS制作类似选项卡切换的年历
2016/12/03 Javascript
原生js实现日期计算器功能
2017/02/17 Javascript
jquery 手势密码插件
2017/03/17 Javascript
详解node.js搭建代理服务器请求数据
2017/04/08 Javascript
element-ui 限制日期选择的方法(datepicker)
2018/05/16 Javascript
bootstrap实现嵌套模态框的实例代码
2020/01/10 Javascript
[06:04]DOTA2英雄梦之声Vol19卓尔游侠
2014/06/20 DOTA
基于python实现的抓取腾讯视频所有电影的爬虫
2016/04/22 Python
Python判断文本中消息重复次数的方法
2016/04/27 Python
老生常谈python的私有公有属性(必看篇)
2017/06/09 Python
flask使用session保存登录状态及拦截未登录请求代码
2018/01/19 Python
Python matplotlib画图时图例说明(legend)放到图像外侧详解
2020/05/16 Python
5行Python代码实现图像分割的步骤详解
2020/05/25 Python
Django Admin 上传文件到七牛云的示例代码
2020/06/20 Python
Django怎么在admin后台注册数据库表
2020/11/14 Python
CSS中越界问题的经典解决方案【推荐】
2016/04/19 HTML / CSS
巴西购物网站:Estrela10
2018/12/13 全球购物
EJB3推出JPA的原因
2013/10/16 面试题
校园招聘策划书
2014/01/09 职场文书
服装仓管员岗位职责
2014/06/17 职场文书
实现中国梦思想汇报2014
2014/09/13 职场文书
2014年大学生社会实践自我鉴定
2014/09/26 职场文书
华清池导游词
2015/02/02 职场文书
电影开国大典观后感
2015/06/04 职场文书
MySQL的意向共享锁、意向排它锁和死锁
2022/07/15 MySQL