MySQL性能优化之(explain)工具

news2024/9/21 0:48:34

慢SQL的定位

在MySQL当中,我们有时候写的SQL执行效率太慢此时我们需要将其优化。但是SQL可能非常的多,难道我们一条一条的进行查看吗?在MySQL当当中我们可以查看慢查询日志,看看那些SQL这么慢。但是这个默认情况下这个慢查询日志是关闭的,我们可以通过一下命令进行查看

show variables like '%query_log%';

执行结果如下:

mysql> show variables like '%query_log%';
+------------------------------+---------------------------------+
| Variable_name                | Value                           |
+------------------------------+---------------------------------+
| binlog_rows_query_log_events | OFF                             |
| slow_query_log               | ON                              |
| slow_query_log_file          | /www/server/data/mysql-slow.log |
+------------------------------+---------------------------------+
3 rows in set (0.01 sec)

我们可以将其开启

set global slow_query_log='ON';

在这里插入图片描述
并且通过上面我们也可以看到慢查询日志在那个路径下。然后了我们可以设置一个业务可以接受的时间,执行时间超过这个值的SQL都将被记录在慢查询日志里面

show variables like '%long_query_time%';

在这里插入图片描述
这里如果我们想把时间缩短,比如设置为 1 秒,可以这样设置:

set global long_query_time = 1;//设置为全局
show global variables like '%long_query_time%';

在这里插入图片描述
同时我们也可以查看一下这个系统当中有多少条这个慢查询日志。

SHOW GLOBAL STATUS LIKE '%Slow_queries%';

在这里插入图片描述
下面我们来建一张表

CREATE TABLE `student` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`stuno` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`classId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

现在我们往表里面插入大量的数据,首先:命令开启:允许创建函数设置:

set global log_bin_trust_function_creators=1; # 不加global只是当前窗口有效。

2.创建函数

DELIMITER //
CREATE FUNCTION rand_string(n INT)
RETURNS VARCHAR(255) #该函数会返回一个字符串
BEGIN
DECLARE chars_str VARCHAR(100) DEFAULT
'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
DECLARE return_str VARCHAR(255) DEFAULT '';
DECLARE i INT DEFAULT 0;
WHILE i < n DO
SET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
SET i = i + 1;
END WHILE;
RETURN return_str;
END //
DELIMITER ;
#测试
SELECT rand_string(10)

产生随机数值:

DELIMITER //
CREATE FUNCTION rand_num (from_num INT ,to_num INT) RETURNS INT(11)
BEGIN
DECLARE i INT DEFAULT 0;
SET i = FLOOR(from_num +RAND()*(to_num - from_num+1)) ;
RETURN i;
END //
DELIMITER ;
#测试:
SELECT rand_num(10,100);

创建存储过程

DELIMITER //
CREATE PROCEDURE insert_stu1( START INT , max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO student (stuno, NAME ,age ,classId ) VALUES
((START+i),rand_string(6),rand_num(10,100),rand_num(10,1000));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END //
DELIMITER ;

最后我们调用存储过程

CALL insert_stu1(100001,4000000);

现在我们的这个数据库里面有大量的数据,下面我们执行一条sql看看这个是否会记录了

SELECT * FROM student WHERE stuno = 3455655;

执行结果如下:

mysql> SELECT * FROM student WHERE stuno = 3455655;
+---------+---------+--------+------+---------+
| id      | stuno   | name   | age  | classId |
+---------+---------+--------+------+---------+
| 3355654 | 3455655 | UyIUzM |   33 |      53 |
+---------+---------+--------+------+---------+
1 row in set (2.38 sec)

mysql> SHOW GLOBAL STATUS LIKE '%Slow_queries%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries  | 1     |
+---------------+-------+
1 row in set (0.00 sec)

获取我们去这个慢查询日志里面看看也可以。

explain SQL执行计划

explain是什么?explain是这个SQL执行官网.使用EXPLAIN关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。
explain的使用方法非常的简单,explain+sql就可以了。下面我们来简单的执行一条

mysql> explain select * from student where id=1000;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | student | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.04 sec)

下面稍微解释一下上面这些字段的含义

  • id:在一个大的查询语句中每个SELECT关键字都对应一个 唯一的id
  • select_type:SELECT关键字对应的那个查询的类型
  • table :表名
  • partitions :匹配的分区信息
  • type :针对单表的访问方法
  • possible_keys: 可能用到的索引
  • key :实际上使用的索引
  • key_len: 实际使用到的索引长度
  • ref :当使用索引列等值查询时,与索引列进行等值匹配的对象信息
  • rows: 预估的需要读取的记录条数
  • filtered:某个表经过搜索条件过滤后剩余记录条数的百分比
  • Extra: 一些额外的信息

在这里一些不太重要的字段,在这里简单说一下这个id和selec_type。每一个select 都会有一个全局的id.select_type表示的查询的类型。

下面我们重点看一下这个type字段。这个字段非常的重要一般常用的基本是这样的
const>eq_ref>ref>range>index>all.性能从高到低。一般我们查询条件一般需要达到range级别。
在这里插入图片描述
下面我们一个一个来解释首先是这个const.这个级别一般很难达到。
const表示通过索引一次就可以找到,const用于比较primary key 或者unique索引。因为只匹配一行,所以很快。如将主键置于where列表当中,MySQL就能将该查询转换为一个常量。
下面我们给个列子表是这样的

mysql> desc student;
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int         | NO   | PRI | NULL    | auto_increment |
| stuno   | int         | NO   |     | NULL    |                |
| name    | varchar(20) | YES  |     | NULL    |                |
| age     | int         | YES  |     | NULL    |                |
| classId | int         | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
5 rows in set (0.06 sec)

下面我们执行一下这条SQL

mysql> explain select * from student where id=1000;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | student | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.04 sec)

我们发现他这个type就是const.

下面是这个eq_ref,这个主要用于这个多表查询。其含义主要是唯一索引扫描对于每个索引列表中只有一条记录与之匹配。常用于主键或者唯一索引扫描。下面我们来执行一下sql

mysql> explain select * from student a,student b where a.id=b.id;
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+---------+----------+-------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref      | rows    | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+---------+----------+-------+
|  1 | SIMPLE      | a     | NULL       | ALL    | PRIMARY       | NULL    | NULL    | NULL     | 3981978 |   100.00 | NULL  |
|  1 | SIMPLE      | b     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | ksy.a.id |       1 |   100.00 | NULL  |
+----+-------------+-------+------------+--------+---------------+---------+---------+----------+---------+----------+-------+
2 rows in set, 1 warning (0.01 sec)

我们发现这个第二个出现这个eq_ref,其实这个也比较好理解。eq_ref - 想象你有两张桌子。表A包含列(id,text),其中id是主键。表B具有相同的列(id,text),其中id是主键。表A包含以下数据:

1, Hello 
2, How are

表B有以下数据:

1, world!
2, you?

想象一下eq_ref为A和B之间的JOIN:

select A.text, B.text where A.ID = B.ID

这个JOIN非常快,因为对于表A中扫描的每一行,表B中只能有一行满足JOIN条件。一个,不超过一个。那是因为B.id是独一无二的。

下面我们在来看看这个ref。在这之前我们需要给上面那张表添加一个索引字段

create index age on student(age);

ref指的是这个非唯一键索引扫描,返回匹配某个值的所有行本质上也是一张索引访问,它返回所有匹配某个单独值的行,可能会找到多个符合条件的行。

mysql> explain select * from student where age=100;
+----+-------------+---------+------------+------+---------------+------+---------+-------+-------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref   | rows  | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+-------+----------+-------+
|  1 | SIMPLE      | student | NULL       | ref  | age           | age  | 5       | const | 82828 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+-------+-------+----------+-------+
1 row in set, 1 warning (0.03 sec)

下面我们在来看看这个range 只检索给定返回的行,使用一个索引来选择行。key列显示了那个索引一般就是你的where语句当中出现了between,<,>,in等查询语句。下面我们来看看这个案例

mysql> explain select * from student where id>1100;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 1990989 |   100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

下面我们在来看看这个index,这个比all要好,他也叫做这个full index all,index和all的区别为index类型只遍历这个索引树,通过比all快因为索引文件通常比数据文件要小也就是说虽然all和index都是读全表但是index是从索引当中读取,all是从硬盘当中读取。所有全索引扫描比全表扫描要快。下面我们看一下例子

mysql> explain select id from student ;
+----+-------------+---------+------------+-------+---------------+------+---------+------+---------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | index | NULL          | age  | 5       | NULL | 3981978 |   100.00 | Using index |
+----+-------------+---------+------------+-------+---------------+------+---------+------+---------+----------+-------------+

最后一个就是这个全表扫描,这个效率最差的一个。在这里就不演示了。

下面我们在来看看这个key_len,和这个rows.这个key_len代表的是使用索引的字节数,在不损失精度的情况下越短越好。这个rows表示大致估算找到所需的记录所要读取的行数。

下面我们重点来看看这个extra字段这个字段很重要。
在这里插入图片描述

下面我们重点看一下上面这些字段,首先我们来看第一个using filesort. 如果出现了这一个字段说明mysql会对数据使用一个外部的索引排序,而不是按照从表内索引的顺序进行读取。MySQL无法利用索引完成的排序操我们叫做文件排序。下面我们通过一个案例来说明一下

mysql> explain select * from student where id>10 order by age;
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-----------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra                       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-----------------------------+
|  1 | SIMPLE      | student | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL | 1990989 |   100.00 | Using where; Using filesort |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)

这这里id是主键索引,age是二级索引。为啥会出现要给using filesort 这个外部排序了?这是因为索引只能被使用一次。这个在日常当中是不能被接受的。我们可以通过简历复合索引来将其优化掉建立一个id和age的联合索引。在这里就不修改这个表来演示

下面一个我们看看这个using temporary 产生了这个临时表这个更加不能接受。使用了这个临时表保存中间结果,MySQL在对查询结果排序时使用临时表常见与排序order by 和分组查询group by。
下面我们来看一个列子

mysql> explain select  age from student where id<1000 group by age;
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+-------------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra                                     |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+-------------------------------------------+
|  1 | SIMPLE      | student | NULL       | range | age,id_age    | id_age | 4       | NULL |  999 |   100.00 | Using where; Using index; Using temporary |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+-------------------------------------------+
1 row in set, 1 warning (0.00 sec)

我们在看Using index这个索引覆盖,什么意思就是在二级索引就能找到不需要再去主键索引找一次

mysql> explain select id,age from student where id<1000;
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | student | NULL       | range | id_age        | id_age | 4       | NULL |  999 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+--------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480914.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sqoop使用

sqoop使用 1. 导入数据2. 从mysql向hive导入数据2.1 导入用户信息表 2.导入订单表2.2 导入订单表2.3 导入商品信息表2.4 导入国家信息表2.5 导入省份信息表2.6 导入城市信息表2.7 创建hive临时表文件 在使用sqoop之前&#xff0c;需要提前启动hadoop, yarn和对应的数据库mysql …

当音乐遇上Python:用Pydub自动分割音频

&#x1f3b5; &#x1f3b5; &#x1f3b5; 当音乐遇上Python&#xff1a;用Pydub自动分割音频 随着短视频应用的普及&#xff0c;越来越多人开始了解并尝试制作自己的短视频作品。而在制作短视频时&#xff0c;背景音乐的选择和使用也是非常重要的一步。很多人喜欢选择一首长…

倒立摆控制器的设计(分别用极点配置,LQR方法,Robust H-无穷方法)

G01倒立摆控制器设计 Author&#xff1a;DargonNote date&#xff1a;2020/12/13课程用书&#xff1a;LMIs in Control Systems Analysis,Design and Applications 1,倒立摆控制系统简介 倒立摆系统是一个复杂的控制系统&#xff0c;具有非线性、强耦合、多变量、不稳定等特…

干货 | 正念,寻求属于你的存在之道

Hello,大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 你是否也曾感到内心无法平静&#xff1f;如果是&#xff0c;不妨了解一下正念&#xff0c;它或许能为你带来改变。 正念作为一种古老的修行方式&#xff0c;如今已经在世界范围内广为流传&#xff0c;…

《Netty》从零开始学netty源码(四十九)之PoolArena

目录 PoolArenaallocate()创建newByteBuf()分配具体的内存空间allocate() PoolArena Netty中分配内存是委托给PoolArena来管理的&#xff0c;它主要有两个实现类&#xff1a; 默认情况下使用的DirectArena&#xff0c;它的数据结构如下&#xff1a; 从属性中我们看到PoolA…

人生若只如初见,你不来看看Django吗

前言 本文介绍python三大主流web框架之一的Django框架的基本使用&#xff0c;如何创建django项目&#xff0c;如何运行django项目以及django项目的目录结构&#xff0c;另外django又是如何返回不同的数据和页面&#xff1f; python三大主流web框架 Python有三大主流的web框架…

JS手写实现Promise.all

Promise.all() 方法接收一个 Promise 对象数组作为参数&#xff0c;返回一个新的 Promise 对象。该 Promise 对象在所有的 Promise 对象都成功时才会成功&#xff0c;其中一个 Promise 对象失败时&#xff0c;则该 Promise 对象立即失败。 本篇博客将手写实现 Promise.all() 方…

用于scATAC-seq有监督分类的Cellcano

细胞类型识别是单细胞数据分析的基本步骤。由于高质量参考数据集的可用性&#xff0c;有监督细胞分类方法在scRNA-seq数据中很受欢迎。染色质可及性分析&#xff08;scATAC-seq&#xff09;的最新技术进步为理解表观遗传异质性带来了新的见解。随着scATAC-seq数据集的不断积累&…

第二节课 Linux和shell命令之文件管理与常用命令

命令执行&#xff0c;没有图形页面 文件权限是重点 1.目录树 windous分盘 CDEF 在Linux系统中并不存在C/D/E/F等盘符&#xff0c;Linux系统中的一切文件都是 从“根&#xff08;/&#xff09;”目录开始的&#xff0c;并按照文件系统层次化标准&#xff08;Filesystem Hie…

C++:计算机操作系统:多线程:高并发中的线程

高并发中的线程 一切要从CPU说起PC 程序计数器从CPU到操作系统从进程到线程 从这篇开始&#xff0c;我将会开启高性能&#xff0c;高并发系列&#xff0c;本篇是给系列的开篇&#xff0c;主要关注 多线程以及线程池。 一切要从CPU说起 你可能会有疑问&#xff0c;讲多线程为何…

西门子AmeSim车辆仿真软件在新能源汽车开发中的应用-软件AmeSim2021版分享

利用Simcenter Amesim提高系统仿真产品设计效率&#xff0c;Simcenter Amesim是一个全球领先的集成、可扩展的机、电、液系统仿真平台。它允许设计工程师虚拟评估和优化系统性能。 提高系统仿真效率 Simcenter Amesim是一个领先的集成、可扩展的系统仿真平台&#xff0c;允许…

汇编语言学习笔记一

常用寄存器类型 通用寄存器 AX&#xff0c;BX&#xff0c;CX&#xff0c;DX&#xff0c;这四个寄存器都是16位的 他们也可以拆分为2个8位的寄存器&#xff0c;如AX可以拆分为AH和AL两个8位的寄存器&#xff0c;其它三个也可以如此。 通用寄存器的使用比较简单&#xff0c;如 …

【HTML5笔记】HTML5语义化标签、音视频标签、表单标签属性

目录 一、HTML5学习 1.1、HTML5语法 1.2、语义化标签 1.3、音视频标签 &#xff08;1&#xff09;音频标签 &#xff08;2&#xff09;视频标签 1.4、input标签type属性 1.5、datalist数据列表 1.6、表单属性 一、HTML5学习 1.1、HTML5语法 HTML5增加了很多的新标签…

【SpringBoot】自定义策略的静态资源访问

文章目录 新建static文件夹&#xff0c;存储图片等资源方式一 Java编码定义方式二 配置中定义 新建static文件夹&#xff0c;存储图片等资源 项目版本信息&#xff1a;SpringBoot版本为2.3.3.RELEASE&#xff0c;JDK1.8 方式一 Java编码定义 配置类实现WebMvcConfigurer接口&…

【五一创作】spring boot starter 编写自己的starter

spring boot starter 编写自己的starter 陈钊 2023-5-1 源码地址&#xff1a; https://gitcode.net/qq_39339588/my-spring-boot-starter.git 封装my-spring-boot-starter 新建springboot工程&#xff0c;来封装为自己的spring-boot-starter 包名&#xff0c;随便写&#xff0…

基于电流控制的并网逆变器(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

操作系统:文件系统

文件系统 文件保护 文件的保护通过口令保护、加密保护、和访问控制等方式实现。其中&#xff0c;口令和加密是为了防止用户文件被他人存取或窃取&#xff0c;而访问控制则用于控制用户对文件的访问方式。 口令保护 口令指用户在建立一个文件时提供一个口令&#xff0c;系统…

算法套路十四——动态规划之背包问题:01背包、完全背包及各种变形

算法套路十四——动态规划之背包问题&#xff1a;01背包、完全背包及各种变形 算法示例一——0/1背包&#xff1a; 0-1背包:有n个物品&#xff0c;第i个物品的体积为w[i]&#xff0c;价值为v[i]&#xff0c;每个物品至多选一个&#xff0c; 求体积和不超过capacity时的最大价值…