干货6500字全面字讲解 Redis 性能优化点!
Posted 侠梦的开发笔记
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了干货6500字全面字讲解 Redis 性能优化点!相关的知识,希望对你有一定的参考价值。
可以用 MGET key1 key2
合并。这样在实际通讯中,请求数也减少了,延时自然得到好转。
如果不能用 multi-key 指令来合并,比如一个 SET
,一个 GET
无法合并。怎么办?
Redis 中有至少这样两个方法能合并多个指令到一个 request 中,一个是 MULTI/EXEC
,一个是 script。前者本来是构建 Redis 事务的方法,但确实可以合并多个指令为一个 request,它到通讯过程如下。至于 script,最好利用缓存脚本的 sha1 hash key 来调起脚本,这样通讯量更小。
这样确实更能减少网络传输时间,不是么?但如此以来,就必须要求这个 transaction / script 中涉及的 key 在同一个 node 上,所以要酌情考虑。
如果上面的方法我们都考虑过了,还是没有办法合并多个请求,我们还可以考虑合并多个 responses。比如把 2 个回复信息合并:
这样,理论上可以省去 1 次回复所用的网络传输时间。这就是 pipeline 做的事情。举个 ruby 客户端使用 pipeline 的例子:
require \'redis\'
@redis = Redis.new()
@redis.pipelined do
@redis.get \'key1\'
@redis.set \'key2\' \'some value\'
end
# => [1, 2]
据说,有些语言的客户端,甚至默认就使用 pipeline 来优化延时问题,比如 node_redis。
另外,不是任意多个回复信息都可以放进一个 TCP 包中,如果请求数太多,回复的数据很长(比如 get 一个长字符串),TCP 还是会分包传输,但使用 pipeline,依然可以减少传输次数。
pipeline 和上面的其他方法都不一样的是,它不具有原子性。所以在 cluster 状态下的集群上,实现 pipeline 比那些原子性的方法更有可能。
小结一下:
使用 unix 进程间通信,如果单机部署 使用 multi-key 指令合并多个指令,减少请求数,如果有可能的话 使用 transaction、script 合并 requests 以及 responses 使用 pipeline 合并 response
所以,尽量不要在生产环境的代码使用这些执行很慢的指令,这一点 Redis 的作者在来禁止使用这个耗时的指令。
除了这些耗时的指令,Redis 中 transaction,script,因为可以合并多个 commands 为一个具有原子性的执行过程,所以也可能占用 Redis 很长时间,需要注意。
如果你想找出生产环境使用的「慢指令」,那么可以利用 SLOWLOG GET count
来查看最近的 count 个执行时间很长的指令。至于多长算长,可以通过在 redis.conf 中设置 slowlog-log-slower-than 来定义。
除此之外,在很多地方都没有提到的一个可能的慢指令是 DEL
,但 redis.conf 文件的访问。检查的方式是:
从中随机取出 20 个 keys 把过期的删掉。 如果刚刚 20 个 keys 中,有 25% 以上(也就是 5 个以上)都是过期的,Redis 认为,过期的 keys 还挺多的,继续重复步骤 1,直到满足退出条件:某次取出的 keys 中没有那么多过去的 keys。
这里对于性能的影响是,如果真的有很多的 keys 在同一时间过期,那么 Redis 真的会一直循环执行删除,占用主线程。
对此,Redis 作者的这个指令,因为它更容易产生 keys 同时过期的现象。我还见到过一些建议是给 keys 的过期时间设置一个随机波动量。最后,redis.conf 中也给出了一个方法,把 keys 的过期删除操作变为异步的,即,在 redis.conf 中设置 lazyfree-lazy-expire yes
。
除了时间性能上的考虑,有时候我们还需要节省存储空间。比如上面提到的 ziplist 结构,就比 hashtable 结构节省存储空间(Redis Essentials 的作者分别在 hashtable 和 ziplist 结构的 Hash 中插入 500 个 fields,每个 field 和 value 都是一个 15 位左右的字符串,结果是 hashtable 结构使用的空间是 ziplist 的 4 倍。)。但节省空间的数据结构,其算法的复杂度可能很高。所以,这里就需要在具体问题面前做出权衡。欢迎关注公众号:朱小厮的博客,回复:1024,可以领取redis专属资料。
如何做出更好的权衡?我觉得得深挖 Redis 的存储结构才能让自己安心。这方面的内容我们下次再说。
以上这三点都是编程层面的考虑,写程序时应该注意啊。下面这几点,也会影响 Redis 的性能,但解决起来,就不只是靠代码层面的调整了,还需要架构和运维上的考虑。
考虑操作系统和硬件是否影响性能Redis 运行的外部环境,也就是操作系统和硬件显然也会影响 Redis 的性能。在官方文档中,就给出了一些例子:
CPU:Intel 多种 CPU 都比 AMD 皓龙系列好 虚拟化:实体机比虚拟机好,主要是因为部分虚拟机上,硬盘不是本地硬盘,监控软件导致 fork 指令的速度慢(持久化时会用到 fork),尤其是用 Xen 来做虚拟化时。 内存管理:在 linux 操作系统中,为了让 translation lookaside buffer,即 TLB,能够管理更多内存空间(TLB 只能缓存有限个 page),操作系统把一些 memory page 变得更大,比如 2MB 或者 1GB,而不是通常的 4096 字节,这些大的内存页叫做 huge pages。同时,为了方便程序员使用这些大的内存 page,操作系统中实现了一个 transparent huge pages(THP)机制,使得大内存页对他们来说是透明的,可以像使用正常的内存 page 一样使用他们。但这种机制并不是数据库所需要的,可能是因为 THP 会把内存空间变得紧凑而连续吧,就像mongodb 的文档[11]中明确说的,数据库需要的是稀疏的内存空间,所以请禁掉 THP 功能。Redis 也不例外,但 Redis 官方博客上给出的理由是:使用大内存 page 会使 bgsave 时,fork 的速度变慢;如果 fork 之后,这些内存 page 在原进程中被修改了,他们就需要被复制(即 copy on write),这样的复制会消耗大量的内存(毕竟,人家是 huge pages,复制一份消耗成本很大)。所以,请禁止掉操作系统中的 transparent huge pages 功能。 交换空间:当一些内存 page 被存储在交换空间文件上,而 Redis 又要请求那些数据,那么操作系统会阻塞 Redis 进程,然后把想要的 page,从交换空间中拿出来,放进内存。这其中涉及整个进程的阻塞,所以可能会造成延时问题,一个解决方法是禁止使用交换空间(Redis Essentials 中如是建议,如果内存空间不足,请用别的方法处理)。
Redis 的一项重要功能就是持久化,也就是把数据复制到硬盘上。基于持久化,才有了 Redis 的数据恢复等功能。
但维护这个持久化的功能,也是有性能开销的。
首先说,RDB 全量持久化。
这种持久化方式把 Redis 中的全量数据打包成 rdb 文件放在硬盘上。但是执行 RDB 持久化过程的是原进程 fork 出来一个子进程,而 fork 这个系统调用是需要时间的,根据Redis Lab 6 年前做的实验[12],在一台新型的 AWS EC2 m1.small^13 上,fork 一个内存占用 1GB 的 Redis 进程,需要 700+ 毫秒,而这段时间,redis 是无法处理请求的。
虽然现在的机器应该都会比那个时候好,但是 fork 的开销也应该考虑吧。为此,要使用合理的 RDB 持久化的时间间隔,不要太频繁。
接下来,我们看另外一种持久化方式:AOF 增量持久化。
这种持久化方式会把你发到 redis server 的指令以文本的形式保存下来(格式遵循 redis protocol),这个过程中,会调用两个系统调用,一个是 write(2)
,同步完成,一个是 fsync(2)
,异步完成。
这两部都可能是延时问题的原因:
write 可能会因为输出的 buffer 满了,或者 kernal 正在把 buffer 中的数据同步到硬盘,就被阻塞了。 fsync 的作用是确保 write 写入到 aof 文件的数据落到了硬盘上,在一个 7200 转/分的硬盘上可能要延时 20 毫秒左右,消耗还是挺大的。更重要的是,在 fsync 进行的时候,write 可能会被阻塞。
其中,write 的阻塞貌似只能接受,因为没有更好的方法把数据写到一个文件中了。但对于 fsync,Redis 允许三种配置,选用哪种取决于你对备份及时性和性能的平衡:
always:当把 appendfsync 设置为 always,fsync 会和客户端的指令同步执行,因此最可能造成延时问题,但备份及时性最好。 everysec:每秒钟异步执行一次 fsync,此时 redis 的性能表现会更好,但是 fsync 依然可能阻塞 write,算是一个折中选择。 no:redis 不会主动出发 fsync (并不是永远不 fsync,那是不太可能的),而由 kernel 决定何时 fsync
以上,我们都是基于单台,或者单个 Redis 服务进行优化。下面,我们考虑当网站的规模变大时,利用分布式架构来保障 Redis 性能的问题。
首先说,哪些情况下不得不(或者最好)使用分布式架构:
数据量很大,单台服务器内存不可能装得下,比如 1 个 T 这种量级 需要服务高可用 单台的请求压力过大
解决这些问题可以采用数据分片或者主从分离,或者两者都用(即,在分片用的 cluster 节点上,也设置主从结构)。
这样的架构,可以为性能提升加入新的切入点:
把慢速的指令发到某些从库中执行 把持久化功能放在一个很少使用的从库上 把某些大 list 分片
其中前两条都是根据 Redis 单线程的特性,用其他进程(甚至机器)做性能补充的方法。
当然,使用分布式架构,也可能对性能有影响,比如请求需要被转发,数据需要被不断复制分发。(待查)
后话其实还有很多东西也影响 Redis 的性能,比如 active rehashing(keys 主表的再哈希,每秒 10 次,关掉它可以提升一点点性能),但是这篇博客已经写的很长了。而且,更重要不是收集已经被别人提出的问题,然后记忆解决方案;而是掌握 Redis 的基本原理,以不变应万变的方式决绝新出现的问题。
【架构】21个软件架构特点解析
【PPT】京东金融大数据平台架构
一次非典型性 Redis 阻塞总结
支持百亿级别的 Java 分布式日志组件EasyLog
基于Redis位图实现用户签到功能
ClickHouse在趣头条中的实战PPT
点赞是最大的支持
Mysql进阶优化篇01——四万字详解数据库性能分析工具(深入全面详细,收藏备用)
前 言
🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端
🍌 专栏简介:mysql进阶,主要讲解mysql数据库进阶知识,包括索引、数据库调优、分库分表等
🌰 文章简介:本文将介绍数据库优化的步骤、思路、性能分析工具,比如慢查询、EXPLAIN
,SHOW PROFILING
等,并且对各个工具执行性能分析结果性能参数都有详细的介绍解释、建议收藏备用。
🍓 相关推荐:
目录
- 1.数据库服务器的优化步骤
- 2.查看系统性能参数
- 3.统计SQL的查询成本:last_query_cost
- 4.定位执行慢的 SQL:慢查询日志
- 5.查看 SQL 执行成本:SHOW PROFILE
- 6.分析查询语句:EXPLAIN(重点)
- 7.EXPLAIN的进一步使用
- 8.分析优化器执行计划:trace
- 9.MySQL监控分析视图-sys schema
1.数据库服务器的优化步骤
数据库的优化整个流程划分成了 观察(Show status) 和 行动(Action) 两个部分。数据库的优化可以总结为下图。字母 S 的部分代表观察(会使用相应的分析工具),字母 A 代表的部分是行动(对应分析可以采取的行动)。
可以从图中看到,在整个流程中需要用到很多分析工具:比如慢查询,EXPLAIN
,SHOW PROFILING
等,这篇文章就会介绍这些数据库性能分析工具。
简单小结如下:
可以看到数据库调优的步骤中越往金字塔尖走,其成本越高,效果越差,因此我们在数据库调优的过程中,要重点把握金字塔底部的sql及索引调优,数据库表结构调优,系统配置参数调优等软件层面的调优。
2.查看系统性能参数
可以使用SHOW STATUS
语句查询一些数据库服务器的性能参数和使用频率。
其语法如下:
SHOW [GLOBAL][SESSION] STATUES LIKE '参数';
一些常用的性能参数如下:
•
Connections
:连接MySQL服务器的次数。
•Uptime
:MySQL服务器的上线时间。
•Slow_queries
:慢查询的次数。
•Innodb_rows_read
:Select查询返回的行数
•Innodb_rows_inserted
:执行INSERT操作插入的行数
•Innodb_rows_updated
:执行UPDATE操作更新的行数
•Innodb_rows_deleted
:执行DELETE操作删除的行数
•Com_select
:查询操作的次数。
•Com_insert
:插入操作的次数。对于批量插入的 INSERT 操作,只累加一次。
•Com_update
:更新操作的次数。
•Com_delete
:删除操作的次数。
举几个例子,玩一把。查看mysql的上线时间
mysql> show status like 'connections';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Connections | 9 |
+---------------+-------+
1 row in set (0.01 sec)
看看存储引擎增删改查的行数。
mysql> show status like 'innodb_rows_%';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| Innodb_rows_deleted | 0 |
| Innodb_rows_inserted | 0 |
| Innodb_rows_read | 8 |
| Innodb_rows_updated | 0 |
+----------------------+-------+
4 rows in set (0.00 sec)
3.统计SQL的查询成本:last_query_cost
先来造一下数据(友情提醒:上一篇文章已经造过,如果您是从上一篇文章跟着阅读过来的,不用重新造了哟。)
CREATE DATABASE atguigudb1;
USE atguigudb1;
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 //
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 //
# 存储过程1:创建插入课程表存储过程
DELIMITER //
CREATE PROCEDURE insert_course( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO course (course_id, course_name ) VALUES
(rand_num(10000,10100),rand_string(6));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END //
DELIMITER ;
# 存储过程2:创建插入学生表存储过程
CREATE PROCEDURE insert_stu( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0; #设置手动提交事务
REPEAT #循环
SET i = i + 1; #赋值
INSERT INTO student_info (course_id, class_id ,student_id ,NAME ) VALUES
(rand_num(10000,10100),rand_num(10000,10200),rand_num(1,200000),rand_string(6));
UNTIL i = max_num
END REPEAT;
COMMIT; #提交事务
END //
# 插入课程数据
CALL insert_course(100);
#插入学生数据
CALL insert_stu(1000000);
执行查询操作并且查看sql执行成本,Value
表示I/O加载的数据页的页数。
mysql> select * from student_info where id = 900001;
+--------+------------+--------+-----------+----------+---------------------+
| id | student_id | name | course_id | class_id | create_time |
+--------+------------+--------+-----------+----------+---------------------+
| 900001 | 128284 | jbCKPX | 10080 | 10001 | 2022-05-31 11:01:54 |
+--------+------------+--------+-----------+----------+---------------------+
1 row in set (0.00 sec)
mysql> show status like 'last_query_cost';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| Last_query_cost | 1.000000 |
+-----------------+----------+
1 row in set (0.00 sec)
再来个大的。
mysql> select * from student_info where id between 900001 and 900100;
+--------+------------+--------+-----------+----------+---------------------+
| id | student_id | name | course_id | class_id | create_time |
+--------+------------+--------+-----------+----------+---------------------+
| 900001 | 128284 | jbCKPX | 10080 | 10001 | 2022-05-31 11:01:54 |
// ...
| 900099 | 45120 | MZOSay | 10081 | 10026 | 2022-05-31 11:01:54 |
| 900100 | 83397 | lQyTXg | 10034 | 10058 | 2022-05-31 11:01:54 |
+--------+------------+--------+-----------+----------+---------------------+
100 rows in set (0.00 sec)
mysql> show status like 'last_query_cost';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| Last_query_cost | 41.136003 |
+-----------------+-----------+
1 row in set (0.00 sec)
不知道大家有没有发现,上面的查询页的数量是刚才的 41 倍,但是查询的效率并没有明显的变化,实际上这两个 SQL 查询的时间基本上一样,查询last_query_cost
对于比较开销是非常有用的,特别是我们有好几种查询方式可选的时候。
🎈 SQL查询是一个动态的过程,从页加载的角度,我们可以得到以下两点结论:
1.位置决定效率:数据库缓冲池>内存>磁盘。
2.批量决定效率:顺序读取>大于随机读取,有时候批量顺序读取多个页甚至会比随机加载一个页更快。
在实际生产中,我们可以利用这个特点,把经常用于查询的数据尽量放在缓冲池中,其次我们可以充分利用磁盘的吞吐能力,批量读取数据。
4.定位执行慢的 SQL:慢查询日志
慢查询日志用来记录相应时间超过阈值的语句,它可以帮助我们发现那些执行时间特别长的sql语句,以期进行针对性优化。一般mysql的慢查询日志默认关闭,非调优情况不建议开启,避免影响数据库的性能。
4.1 开启慢查询日志
1️⃣开启slow_query_log
查看
mysql> show variables like '%slow_query_log%';
+---------------------+------------------------------------------------------+
| Variable_name | Value |
+---------------------+------------------------------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | D:\\mysql-5.7.26-winx64\\data\\DESKTOP-1PB99O1-slow.log |
+---------------------+------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
修改,注意这里要加global
,因为它是全局系统变量,否则会报错哟。
mysql> set global slow_query_log='ON';
Query OK, 0 rows affected (0.02 sec)
再查看。
mysql> show variables like '%slow_query_log%';
+---------------------+------------------------------------------------------+
| Variable_name | Value |
+---------------------+------------------------------------------------------+
| slow_query_log | ON |
| slow_query_log_file | D:\\mysql-5.7.26-winx64\\data\\DESKTOP-1PB99O1-slow.log |
+---------------------+------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
2️⃣修改long_query_time阈值
查看。
mysql> show variables like '%long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set, 1 warning (0.02 sec)
修改。
mysql> set global long_query_time = 1;
Query OK, 0 rows affected (0.00 sec)
再查看。
mysql> show global variables like '%long_query_time%';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
1 row in set, 1 warning (0.00 sec)
🔊记得要加global
,否则默认只在当前会话,不过,即使加global
上面的修改还都只是临时的修改,当数据库服务器重启以后,以上修改就会失效。要想永久的生效,需要更改my.cnf
文件,然后重启数据库服务器。
slow_query_log=ON
slow_query_log_file=/var/lib/mysql/atguigu-slow.log
long_query_time=3
log_output=FILE
4.2 案例演示
1️⃣ 建表
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;
2️⃣ 设置参数 log_bin_trust_function_creators
(第3节已经完成)
创建函数,假如报错
This function has none of DETERMINISTIC......
命令开启:允许创建函数设置:
set global log_bin_trust_function_creators=1; # 不加global只是当前窗口有效。
3️⃣创建函数
(第3节已经完成)
随机产生字符串:
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);
产生随机数值(第3节已经完成):
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);
4️⃣创建存储过程
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 ;
步骤5:调用存储过程
#调用刚刚写好的函数, 4000000条记录,从100001号开始
mysql> CALL insert_stu1(100001,4000000);
Query OK, 0 rows affected (10 min 47.03 sec)
注意,这个时间会比较长,请耐心等待几分钟哟。结束后可以查询下是不是插入成功了。
select count(*) from student;
📘 有一个小细节在这里提下,就是上面查询数据量的语句在存储引擎使用
MyISAM
时会比使用InnoDB
时快很多,这是因为MyISAM存储引擎会有字段专门表示记录数。
接下来执行一下下面的查询操作,制造慢查询的场景。
mysql> set long_query_time = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM student WHERE stuno = 3455655;
+---------+---------+--------+------+---------+
| id | stuno | name | age | classId |
+---------+---------+--------+------+---------+
| 3355654 | 3455655 | QQFFkl | 57 | 904 |
+---------+---------+--------+------+---------+
1 row in set (3.47 sec)
mysql> select * from student where name = 'QQFFkl';
+---------+---------+--------+------+---------+
| id | stuno | name | age | classId |
+---------+---------+--------+------+---------+
| 143213 | 243214 | qQffkL | 95 | 543 |
| 225733 | 325734 | qQffkL | 10 | 861 |
| 280275 | 380276 | QqfFKL | 50 | 118 |
| 1355465 | 1455466 | QqfFKL | 52 | 195 |
| 1676763 | 1776764 | qQffkL | 11 | 906 |
| 1766208 | 1866209 | qqFfKl | 11 | 396 |
| 1870789 | 1970790 | qqFfKl | 97 | 182 |
| 2368740 | 2468741 | QQFFkl | 51 | 645 |
| 2386799 | 2486800 | qQffkL | 11 | 875 |
| 3170932 | 3270933 | QqfFKL | 50 | 92 |
| 3355654 | 3455655 | QQFFkl | 57 | 904 |
| 3966226 | 4066227 | qQffkL | 96 | 629 |
+---------+---------+--------+------+---------+
查看下慢查询的记录。
mysql> show status like 'slow_queries';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries | 2 |
+---------------+-------+
1 row in set (0.00 sec)
🎯补充:在Mysql中,还有另外一个变量
min_examined_row_limit
用来控制慢查询日志,他的含义是,在查询时,查询时间超过long_query_time
的日志,还要保证查询扫描过的记录数满足min_examined_row_limit
才会被记录到慢查询日志。一般它默认是0,我们也一般不会去修改它。SHOW VARIABLES like 'min%' OK 时间: 0.002s