四、查询截取分析

643 阅读17分钟

SQL 分析基本操作

① 观察一天查看生产环境 SQL 慢的情况;

② 开启慢查询日志,设置阈值,如超过 5s 的就是慢查询,并抓取 SQL;

③ 使用 EXPLAIN + SQL 语句 查看慢SQL;

④ 使用 show profile 进行进一步分析;

⑤ 运维或DBA 进行 SQL 服务器参数调优;

小表驱动大表

使用小表驱动大表,类似于多层循环,最外层最好循环次数要少,否则会消耗很长时间。同理当 MySQL 进行 CRUD 操作时会进行锁表操作时应当使用小的结果集驱动大的结果集。

select * from A where id in (select id from B) 等价于
for select id from B
for select * from A where A.id = B.id

当 B表的数据集必须小于 A表的数据集时,使用 in 优于 exists

select * from A where exists (select 1 from B where B.id = A.id) 等价于
for select * from A
for select * from B where B.id = A.id

当 A表数据集小于 B表数据集时,使用 exists 优于 in

exists 语法 select... from table where exists (subquery)

可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(TRUE、FALSE)来决定结果是否保留。

exists(subquery) 只返回 TRUE、FALSE,因此子查询中的条件字段可以是 SELECT 1SELECT X,官方的解释是在实际执行时会忽略 SELECT 清单,因此没有区别;

exists 子查询的实际执行过程可能经过了优化而不是逐条对比;

exists 子查询也可以使用条件表达式、其他子查询或者 JOIN 来替代,需要根据具体问题具体分析;

1. 查询优化

1.1 关联查询优化

1.1.1 左/右连接

① 优化关联查询时需要在被驱动表上建立索引才能提高性能;

② 尽可能减少 Join 语句中的 NestedLoop 的循环次数;“用小结果集驱动大结果集”

③ 优先优化 NestedLoop 的内层字段;

④ 当无法保证驱动表的 JOIN 字段被索引且内存充足的条件下,可以适当调整 JoinBuffer 设置;

驱动表和被驱动表:

LEFT JOIN 查询时,左侧的表为驱动表右侧的表为被驱动表;

RIGHT JOIN 查询时,右侧的表为驱动表左侧的表为被驱动表;

**示例:**在 book 表的 card 列建立单值索引

image-20210419094550229

通过上面的 SQL 查询可以看出建立在 book 表的 card 列的单值索引,在右连接作为驱动表时被使用,将查询的列从 40 条降低到1条。

1.1.2 内关联

在使用 INNER JOIN 时 MySQL 会自动将小结果集的表作为驱动表;

STRSAIGHT_JOIN 效果和 INNER JOIN 一样,但是会强制将左侧作为驱动表

**示例:**在 book 表的 card 列建立单值索引

image-20210419092331602

通过上面的 SQL 可以看到 MySQL 对于 inner join 会自动选择结果集小的表作为驱动表,左右表无论那个建立索引都会被使用。

image-20210419093217786

通过上面 SQL 可以看到,straight_join 会强制将左侧的表作为驱动表,会导致建立索引的表失效。

1.1.3 多表嵌套关联

子查询尽量不要放在被驱动表,有可能不能使用索引;

LEFT JOIN 时尽量让实体表作为被驱动表;

1.2 子查询优化

在进行范围判断时,尽量不要使用 NOT INNOT EXISTS,使用 LEFT JOIN ON XXXX IS NULL 代替。

1.3 排序分组优化

order by 子句尽量使用 index 方式排序,避免使用 filesort 方式进行排序。

① 建立数据库表

# 建立数据库表
create table tblA(
#id int primary key not null auto_increment,
age int,
birth timestamp not null
);
insert into tblA(age, birth) values(22, now());
insert into tblA(age, birth) values(23, now());
insert into tblA(age, birth) values(24, now());
# 在 tablA 表建立复合索引
create index idx_A_ageBirth on tblA(age, birth);
# 查询数据表
mysql> select * from tblA;
+------+---------------------+
| age  | birth               |
+------+---------------------+
|   22 | 2021-04-19 10:04:26 |
|   23 | 2021-04-19 10:04:26 |
|   24 | 2021-04-19 10:04:29 |
+------+---------------------+
3 rows in set (0.00 sec)
# 查询索引
mysql> show index from tblA;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name       | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tbla  |          1 | idx_A_ageBirth |            1 | age         | A         |           3 |     NULL | NULL   | YES  | BTREE      |         |               |
| tbla  |          1 | idx_A_ageBirth |            2 | birth       | A         |           3 |     NULL | NULL   |      | BTREE      |         |               |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.01 sec)

② 分析 SQL 查询

1)范围后排序

image-20210419103244216

索引顺序和查询使用顺序保持一致,遵循最佳左前缀法则,使用了索引,且使用了覆盖索引。

image-20210419103354185

索引顺序和查询使用顺序保持一致,遵循最佳左前缀法则,使用了索引,且使用了覆盖索引。

image-20210419103512819

age 字段进行了范围查询,导致索引失效,转而进行了文件排序,性能开销较大。

2)直接排序(ORDER BY 默认为升序)

image-20210419113806004

索引为复合索引,但是 age 没有被使用,而是直接使用 birth 进行排序,所以使用了文件排序。

image-20210419114244252

使用了覆盖索引,索引列 age 参与排序,索引列 birth 参与条件查询

③ 总结

MySQL 支持两种排序方式,indexfilesortindex 的效率更高,它使用 MySQL 扫描索引完成排序,filesort 的效率比较低,它在进行文件排序会进行大量的 IO 操作严重影响数据库性能。

ORDER BY 满足两种情况时,会使用 index 方式进行排序:

  • ORDER BY 语句使用索引最左前列;
  • 使用 WHERE 子句与 ORDER BY 子句条件列满足索引最左前列;

建议:尽可能在索引列上完成排序操作,遵循最佳左前缀法则

ORDER BY 能使用索引的情况:

ORDER BY 能使用索引的最左前缀;

WHERE 使用索引的最左前缀定义为常量,此时 ORDER BY 能使用索引;

ORDER BY 不能使用索引的情况:

① 排序不一致的时候;

② 不满足最佳左前缀法则(带头大哥不能死,中间兄弟不能断)

ORDER BY 后面的某个字段不是索引列;

WHERE 条件中使用 IN,对于排序而言多个相等条件等同于范围查询;

1.3.1 无过滤不索引

wherelimit 都相当于一种过滤条件,所以才能使用索引。

image-20210419113611641

索引为复合索引,但是 age 没有被使用,而是直接使用 birth 进行排序,所以使用了文件排序。

1.3.2 顺序错必排序

ORDER BY 后面的字段顺序不可以随意调整,会导致索引失效。

image-20210419111249725

复合索引的建立顺序是 agebirth 但是在 ORDER BY 时复合索引建立的顺序被破坏,导致 MySQL 进行了文件排序,数据库性能开销较大。

1.3.3 方向反必排序

就是前一个字段使用正序排序,后一个字段使用倒序排序。如果排序的字段,顺序存在差异,就需要将差异的部分进行倒置排序,因此还是需要手动排序。

image-20210419114533320

age 字段排序为 ASC 升序排序,birth 字段为 DESC 降序排序,需要对原先排序好的数据进行倒置,导致使用文件排序。

1.3.4 索引的选择

两个索引同时存在时,MySQL 选择的索引。

所有的排序都是在条件过滤后才执行的,所以如果条件过滤掉大部分数据的话,千百条数据进行排序的性能开销并不是很大,即使使用索引进行优化排序对实际的性能提升也是有有限的。使用范围查询过滤掉大部分数据和对几万条数进行排序相比,在范围排序中使用索引后对服务器性能开销更小。

当范围条件和 GROUP BYORDER BY 的字段出现二选一时, 优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据不多时,优先在范围字段上加索引。反之同样操作。

1.3.5 使用覆盖索引

覆盖索引可以解决使用 LIKE 进行模糊查询时造成的索引失效问题;

覆盖索引也可以解决使用 !=、<> 导致的索引失效问题;

覆盖索引:SQL 只需要通过索引就可以查询到所需的数据,而不不需要通过二级索引查询到主键后再查询数据。

1.3.6 文件排序详解

MySQL 中的文件排序算法

双路排序算法:

也就是进行两次磁盘扫描,最终得到数据,读取行指针和 ORDER BY 列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。从磁盘取排序字段,在 buffer 中进行排序再从磁盘取出其他字段。

单路排序算法:

从磁盘读取查询需要的所有列,按照 OREDER BY 列在 buffer 对他们进行排序,然后扫描排序后的列表进行输出效率相比双路排序会更快一些,避免额数据的二次读取。将随机 IO 变为顺序 IO,但是需要使用更多的空间

单路排序算法存在的问题:

sort_buffer 中,单路排序算法比双路排序算法需要占用更多的空间,因为单路排序算法将所有字段全部取出,所以有可能导致取出的数据总大小超出了 sort_buffer 的容量,导致每次只能取出 sort_buffer 容量大小的数据进行排序(创建 tmp 文件,进行多路合并)排完后再取出 sort_buffer 容量大小的数据,再进行排序,从而导致进行了多次 IO 操作。

如何优化 MySQL 配置

① 增加 sort_buffer_size 参数设置

无论采用哪种算法,提高 sort_buffer_size 参数都会提高效率,可以根据系统情况进行适当的调整,建议 “1M-8M” 之间。

② 增大 max_length_for_data 参数设置

MySQL 使用单路排序的前提是排序的字段大小要小于 max_length_for_data,提高这个参数可以增加使用单路排序算法的概率。但是如果设置的过高,数据总容量超出 sort_buffer_size 的概率会增加,造成很高的磁盘 IO 操作和很低的处理器使用率。建议在**“1024-8192”**之间调整

③ 减少 select 后面的查询字段,最好不要用 select *

query 的字段大小总和小于 max_length_sort_data 且排序字段不是 TEXT|BLOB 类型时,会使用单路排序算法,否则使用双路排序算法。

两种排序算法的数据都有可能超出 sort_buffer 的容量,超出后会创建 tmp 文件进行合并排序,导致多次 IO,但是使用单路排序算法的风险会大一些,因此要提高 sort_buffer_size.

1.3.7 分组优化

分组的前提是排序,因此 GROUP BY 使用索引的原则几乎和 ORDER BY 使用索引的原则一致,唯一的区别是 GROUP BY 中即使没有过滤条件用到索引,也可以直接使用索引。

WHERE 的效率高于 HAVING,能在 WHERE 中过滤掉的条件没有必要在 HAVING 中进行限定。

2. 慢查询日志

2.1 慢查询日志介绍

MySQL 的慢查询日志是 MySQL 提供的一种日志记录,用来记录在 MySQL 中响应时间超过阈值的语句,具体指运行时间超过 long_query_time 值的 SQL,会被记录到慢查询日志中。long_query_time 值的默认值是10s,也就是运行时间超过 10s 的 SQL 会被记录到慢查询日志中。通过慢查询日志可以帮助我们定位到存在问题的 SQL,结合 EXPLAIN 对 SQL 语句进行分析优化。

2.2 使用慢查询日志

MySQL 默认情况下是没有开启慢查询日志的,需要手动设置参数。如果不需要进行 SQL 调优的话不建议开启此参数,因为慢查询日志会影响性能,慢查询日志支持将日志记录写入文件。

开启慢查询日志

① 查看慢查询日志是否开启:

mysql> SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-------------------------------------------------+
| Variable_name       | Value                                           |
+---------------------+-------------------------------------------------+
| slow_query_log      | OFF                                             |
| slow_query_log_file | /var/lib/mysql/izuf6h7blj36dmxbmcj15wz-slow.log |
+---------------------+-------------------------------------------------+
2 rows in set (0.00 sec)

参数说明:

  • 默认情况下 slow_query_log 的值为 OFF,即慢查询日志是禁用的。
  • 关于慢查询参数 slow_query_log_file,它是指定慢查询日志文件的存放路径,系统会默认给一个缺省的文件 host_name-slow.log(如果没有指定参数 slow_query_log_file 的话)

Tips:MySQL 为了保证性能大多数的功能都是禁用的

② 开启慢查询日志:

set global slow_query_log=1;

使用此命令仅对当前数据库生效,如果 MySQL 重启则会失效,即慢查询日志功能再次关闭。

③ 查看慢查询设定的查询阈值:

mysql> show variables like 'long_query_time%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)

单位秒

假如运行时间正好等于 long_query_time 的情况,并不会被记录下来,也就是说只有查询的 SQL 的时间大于设定的阈值才会被记录。

③ 设定慢查询阈值:

set long_query_time = xxxx

# 查看默认设置的慢查询阈值时间
mysql> show variables like '%long_query_time%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
# 设定慢查询的阈值时间
mysql> set long_query_time = 3;
Query OK, 0 rows affected (0.00 sec)
# 查看设置后的慢查询阈值时间
mysql> show variables like '%long_query_time%';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 3.000000 |
+-----------------+----------+
1 row in set (0.00 sec)

也可以通过向 my.cnf 文件中添加参数来修改;

设置后查询发现设定的时间没有生效的原因:

  • 重新连接或打开新的会话才能看到修改后的值,命令:show variables like 'long_query_time%';
  • 或者使用新的命令查看 show global variables like 'long_query_time%';

④ 查询当前系统中有多少条慢查询记录

show global status like '%slow_queries%'

mysql> show global status like '%slow_queries%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Slow_queries  | 2     |
+---------------+-------+
1 row in set (0.00 sec)

⑤ 通过修改配置文件实现永久修改

my.cnf 文件中找到下面的位置复制以下代码,根据自己的实际情况配置参数和日志输出位置。

[mysqld]
slow_query_log=1
slow_query_log_file=/var/lib/mysql/xxx-slow.log
long_query_time=3
log_output=FILE

配置详解:

slow_query_log:开启/关闭慢查询日志;

slow_query_log_file:慢查询日志文件输出位置和名称;

long_query_time:慢查询 SQL 时间阈值;

log_output:慢查询日志输出格式:

  • 可以是 FILE(存储在数据库的数据文件中的 host_name.log 文件)
  • 也可以是 TABLE(存储在数据库中的 mysql.general_log

2.3 日志分析工具

在生产环境中,如果要手工分析日志,查找、分析 SQL,会很浪费时间,MySQL 提供了日志分析工具 mysqldumpslow

mysqldumpslow 帮助信息详解

参数含义
s表示按照何种方式进行排序
c访问次数
l锁定时间
r返回记录
t查询时间
al平均锁定时间
ar平均返回记录数
at平均查询时间
t返回前面多少条数据
g后面搭配一个正则匹配模式,大小写不敏感

MySQL 进程查看工具 SHOW PROCESS

查询 MySQL 进程列表,杀掉故障进程回收资源。

查看日志:

① 获取返回记录集中最多的 10 个 SQL

mysqldumpslow -s r -t 10 /var/lib/mysql/test-slow.log

② 获取访问次数最多的 10 个 SQL

mysqldumpslow -s c -t 10 /var/lib/mysql/test-slow.log

③ 获取按照时间排序的前 10 条包含左连接的查询语句

mysqldumpslow -s t 10 -g "left join" /var/lib/mysql/test-slow.log

④ 建议在执行以上命令时结合 | more 使用,防止打印的数据过长

mysqldumpslow -s r -t 10 /var/lib/test-slow.log | more

3. 批量数据脚本

总结 SQL 创建各种

创建表:create table

创建索引:create index

创建函数:create function

创建视图:create view

建立两张数据库表并插入 50w 条数据进行压力测试

3.1 建立数据库表

创建 dept 表和 emp

CREATE TABLE `dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
ceo INT NULL ,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
# 1.1创建员工表
CREATE TABLE `emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`empno` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

3.2 配置数据库参数

查看参数是否开启 show variables like 'log_bin_trust_function_creators';

打开参数 set global log_bin_trust_function_creators = 1

# 查看参数是否开启
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF   |
+---------------------------------+-------+
1 row in set (0.00 sec)
# 开启参数
mysql> set global log_bin_trust_function_creators = 1;
Query OK, 0 rows affected (0.00 sec)
# 再次查看参数是否开启
mysql> show variables like 'log_bin_trust_function_creators';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | ON    |
+---------------------------------+-------+
1 row in set (0.00 sec)

当二进制日志启用后,这个变量就会启用,这个变量是控制 MySQL 是否信任存储函数的创建者,不会创建写入二进制日志引起不安全事件的存储函数。参数默认设置为 OFF,用户不得创建或修改存储函数,除非操作用户具有除去 CREATE ROUTINEALTER ROUTINE 特权之外的 SUPER 权限。设置为 OFF 还强制使用 DETERMINISTIC 特性或 READS SQL DATANO SQL 特性声明函数的限制。 如果变量设置为 ON,MySQL 不会对创建存储函数实施这些限制。 此变量也适用于触发器的创建。

当我们开启二进制日志后,如果变量 log_bin_trust_function_creators 的设置为 OFF,则在创建存储函数时会报错 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)

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:设置结束字符。MySQL 默认的结束字符是 ; 但是在编写函数时会使用到,避免函数无法完全被执行,将结束符号替换为 $$

② 随机产生编号

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$$

③ 删除函数

# 删除随机产生字符串的函数
drop function rand_string
# 删除随机产生编号的函数
drop function rand_num;

3.4 创建存储过程

① 创建向 emp 表中插入数据的存储过程

DELIMITER $$
CREATE PROCEDURE insert_emp( START INT , max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
#set autocommit =0 把autocommit 设置成0
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO emp (empno, NAME ,age ,deptid ) VALUES ((START+i) ,rand_string(6) ,
rand_num(30,50),rand_num(1,10000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$

② 创建向 dept 表中插入数据的存储过程

DELIMITER $$
CREATE PROCEDURE `insert_dept`( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
SET autocommit = 0;
REPEAT
SET i = i + 1;
INSERT INTO dept ( deptname,address,ceo ) VALUES (rand_string(8),rand_string(10),rand_num(1,500000));
UNTIL i = max_num
END REPEAT;
COMMIT;
END$$

3.5 调用存储过程

① 调用存储过程向 dept 表插入 1w 条数据

DELIMITER ;
CALL insert_dept(10000);

② 调用存储过程向 emp 表插入 50w 条数据

DELIMITER ;
CALL insert_emp(100000,500000);

4. Show profile

SQL 查询问题排查基本步骤:

① 监控系统中收到当前系统中的 SQL 异常信息;

② 打开慢查询日志,抓取存在问题的 SQL ;

③ 对存在问题的 SQL 使用 EXPLAIN 关键字进行 SQL 分析;

④ 使用 show profile 继续排查 SQL 问题;

⑤ 调整 MySQL 的参数配置;

4.1 Show profile 介绍

是 MySQL 提供的可用于分析当前会话中语句执行的资源消耗情况。可以用于 SQL 的调优测量工具,默认情况下参数处于关闭状态,并保存最近 15 次的运行结果。可以使用 show profile 查看 SQL 的执行周期。

4.2 分析步骤

① 查看是否开启

show variables like '%profiling%'

② 开启功能

set profiling = 1

③ 运行 SQL 语句

④ 查看运行结果

查看全部查询记录:show profiles

mysql> show profiles;
+----------+------------+----------------------------------------------------------+
| Query_ID | Duration   | Query                                                    |
+----------+------------+----------------------------------------------------------+
|        1 | 0.00040950 | show variables like '%profiling%'                        |
|        2 | 0.00006050 | show profies                                             |
|        3 | 0.00008050 | select * from tbl_emp                                    |
|        4 | 0.12290000 | select * from emp group by id limit 150000               |
|        5 | 1.03373300 | select * from emp left join dept on emp.deptid = dept.id |
+----------+------------+----------------------------------------------------------+
5 rows in set (0.00 sec)

查看具体的某条查询记录:show profile cpu,block io for query Query_id

status 参数信息

参数含义
ALL显示所有的开销信息
BLOCK IO显示块 IO 相关开销信息
CONTEXT SWITCHES显示上下文切换相关开销信息
CPU显示 CPU 相关开销信息
IPC显示发送和接收相关开销信息
MEMORY显示内存相关开销信息
PAGE FAULTS显示页面错误相关开销信息
SOURCE显示和 Source_function,Source_file,Source_file 相关开销信息
SWAPS显示交换次数相关开销信息

⑤ 诊断 SQL

通过查看 SQL 语句运行时资源的消耗情况,结合 EXPLAIN 语句分析 SQL 中存在的问题对 SQL 进行优化。

4.3 总结

status 中出现以下语句则表示 SQL 存在问题需要优化:

converting HEAP to MyISAM 查询结果过大,内存不够用转而存储到硬盘;

Create tmp table 创建临时表,主要作用:拷贝数据到临时表,使用完成后删除临时表;

Copy to tmp table on disk 将内存中临时表复制到磁盘,严重影响性能;

locked 锁;

5. 全局慢查询

5.1 配置启用

my.cnf 文件中找到下面的部分,放到对应位置

[mysqld]
# 开启
general_log=1
# 记录日志文件路径
general_log_file=/path/logfile
# 输出格式
log_output=FILE

5.2 编码启用

① 开启全局慢查询

set global_log=1;

set global_log_output='table';

② 查看所有的查询记录

开启后所编写的 SQL 语句,将会记录到 MySQL 库中的 general_log

使用命令 select * from mysql.general_log 查看

注意事项:不要在生产环境开启慢查询日志,会消耗资源导致性能下降影响系统运行。