[TOC] #### 1. 慢查询介绍 ---- 常见面试题:如何从一个大项目中,迅速定位执行速度慢的 SQL 语句? 此时可以使用慢查询定位执行较慢 SQL 语句 慢查询就是在日志中记录运行比较慢的 SQL 语句,是指所有执行超过 long_query_time 参数设定的时间阈值的 SQL 语句查询 #### 2. 慢查询状态 --- ``` # 查看是否开启慢查询日志 ON 1 开启 OFF 0 关闭(默认是关闭的) show variables like 'slow_query_log'; # 开启慢查询日志 set global slow_query_log = 1; # 关闭慢查询日志 set global slow_query_log = 0; ``` ![](https://img.itqaq.com/art/content/79a83d51631c6d720a3f5945d6aaf735.png) 使用下面命令开启慢查询时,当重启 mysql 服务后,慢查询会恢复到默认的关闭状态 ``` set global slow_query_log = 1; ``` 慢查询状态想要永久生效,就必须修改配置文件 my.conf,将下面配置项放入配置文件 my.conf 中,重启 mysql 服务即可生效 ``` slow_query_log = 1 ``` ![](https://img.itqaq.com/art/content/e4d1c83f0f580f3d5f99dec9c1e862ad.png) #### 3. 慢查询时间阈值 --- 上面在介绍慢查询时,已经说明慢查询日志中记录的是超出时间阈值的 SQL 语句 这个时间阈值可以通过下面这个命令查看,默认是 10 秒 ``` # 查看当前慢查询时间阈值 show variables like 'long_query_time'; # 临时修改慢查询时间阈值 (1 秒) set long_query_time = 1; ``` ![](https://img.itqaq.com/art/content/9d422dfc4a882ef51d68d8b61dcd1a14.png) 在配置文件 my.conf 中添加配置项,使设置的时间阈值永久生效 ``` long_query_time = 2 ``` ![](https://img.itqaq.com/art/content/888897b0fea8ef5c01e891a74aed0710.png) #### 4. 构建大表,测试慢查询 --- 创建一个数据库,执行下面 SQL ``` CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ dname VARCHAR(20) NOT NULL DEFAULT "", /*名称*/ loc VARCHAR(13) NOT NULL DEFAULT "" /*地点*/ ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; CREATE TABLE emp( empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*编号*/ ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/ job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/ mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/ hiredate DATE NOT NULL,/*入职时间*/ sal DECIMAL(7,2) NOT NULL,/*薪水*/ comm DECIMAL(7,2) NOT NULL,/*红利*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/ )ENGINE=MyISAM DEFAULT CHARSET=utf8 ; CREATE TABLE salgrade ( grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, losal DECIMAL(17,2) NOT NULL, hisal DECIMAL(17,2) NOT NULL )ENGINE=MyISAM DEFAULT CHARSET=utf8; -- 测试数据 INSERT INTO salgrade VALUES (1,700,1200); INSERT INTO salgrade VALUES (2,1201,1400); INSERT INTO salgrade VALUES (3,1401,2000); INSERT INTO salgrade VALUES (4,2001,3000); INSERT INTO salgrade VALUES (5,3001,9999); # 创建存储过程 delimiter $$ create function rand_string(n INT) returns varchar(255) #该函数会返回一个字符串 begin #chars_str定义一个变量 chars_str,类型是 varchar(100),默认值’abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ’; 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 procedure insert_emp2(in start int(10),in max_num int(10)) begin declare i int default 0; #set autocommit =0 把autocommit设置成0 set autocommit = 0; repeat set i = i + 1; insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,floor(rand()*5+5)); until i = max_num end repeat; commit; end $$ delimiter ; # 调用刚刚写好的函数, 1800000条记录,从100001号开始 call insert_emp2(100001,4000000); ``` 查询 emp 表数据,执行 1.55 秒 ``` mysql> select * from emp; +--------+--------+----------+-----+------------+---------+--------+--------+ | empno | ename | job | mgr | hiredate | sal | comm | deptno | +--------+--------+----------+-----+------------+---------+--------+--------+ | 100002 | BzVfMu | SALESMAN | 1 | 2022-05-15 | 2000.00 | 400.00 | 8 | | 100003 | wcUtjQ | SALESMAN | 1 | 2022-05-15 | 2000.00 | 400.00 | 7 | | ... | ... | ... | ... | ... | ... | ... | ... | +--------+--------+----------+-----+------------+---------+--------+--------+ 4000000 rows in set (1.55 sec) ``` ``` # 查看慢查询日志文件存放位置 show variables like 'slow_query_log_file'; ``` 设置 long_query_time = 1,此时会生成慢查询日志,文件内容如下所示 ``` # Time: 2022-05-15T02:31:37.897427Z # User@Host: root[root] @ localhost [] Id: 2 # Query_time: 1.548641 Lock_time: 0.000156 Rows_sent: 4000000 Rows_examined: 4000000 SET timestamp=1652581897; select * from emp; ```