MySQL 慢查詢詳解

作者:辰風(fēng)沐陽 閱讀:1599 發(fā)布時(shí)間:2022-05-14 上次更新:2022-05-19

1. 慢查詢介紹


常見面試題:如何從一個(gè)大項(xiàng)目中,迅速定位執(zhí)行速度慢的 SQL 語句?

此時(shí)可以使用慢查詢定位執(zhí)行較慢 SQL 語句

慢查詢就是在日志中記錄運(yùn)行比較慢的 SQL 語句,是指所有執(zhí)行超過 long_query_time 參數(shù)設(shè)定的時(shí)間閾值的 SQL 語句查詢

2. 慢查詢狀態(tài)


  1. # 查看是否開啟慢查詢?nèi)罩?ON 1 開啟 OFF 0 關(guān)閉(默認(rèn)是關(guān)閉的)
  2. show variables like 'slow_query_log';
  3. # 開啟慢查詢?nèi)罩?set global slow_query_log = 1;
  4. # 關(guān)閉慢查詢?nèi)罩?set global slow_query_log = 0;

使用下面命令開啟慢查詢時(shí),當(dāng)重啟 mysql 服務(wù)后,慢查詢會恢復(fù)到默認(rèn)的關(guān)閉狀態(tài)

  1. set global slow_query_log = 1;

慢查詢狀態(tài)想要永久生效,就必須修改配置文件 my.conf,將下面配置項(xiàng)放入配置文件 my.conf 中,重啟 mysql 服務(wù)即可生效

  1. slow_query_log = 1

3. 慢查詢時(shí)間閾值


上面在介紹慢查詢時(shí),已經(jīng)說明慢查詢?nèi)罩局杏涗浀氖浅鰰r(shí)間閾值的 SQL 語句

這個(gè)時(shí)間閾值可以通過下面這個(gè)命令查看,默認(rèn)是 10 秒

  1. # 查看當(dāng)前慢查詢時(shí)間閾值
  2. show variables like 'long_query_time';
  3. # 臨時(shí)修改慢查詢時(shí)間閾值 (1 秒)
  4. set long_query_time = 1;

在配置文件 my.conf 中添加配置項(xiàng),使設(shè)置的時(shí)間閾值永久生效

  1. long_query_time = 2

4. 構(gòu)建大表,測試慢查詢


創(chuàng)建一個(gè)數(shù)據(jù)庫,執(zhí)行下面 SQL

  1. CREATE TABLE dept( /*部門表*/
  2. deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*編號*/
  3. dname VARCHAR(20) NOT NULL DEFAULT "", /*名稱*/
  4. loc VARCHAR(13) NOT NULL DEFAULT "" /*地點(diǎn)*/
  5. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
  6. CREATE TABLE emp(
  7. empno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, /*編號*/
  8. ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/
  9. job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/
  10. mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上級編號*/
  11. hiredate DATE NOT NULL,/*入職時(shí)間*/
  12. sal DECIMAL(7,2) NOT NULL,/*薪水*/
  13. comm DECIMAL(7,2) NOT NULL,/*紅利*/
  14. deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部門編號*/
  15. )ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
  16. CREATE TABLE salgrade (
  17. grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,
  18. losal DECIMAL(17,2) NOT NULL,
  19. hisal DECIMAL(17,2) NOT NULL
  20. )ENGINE=MyISAM DEFAULT CHARSET=utf8;
  21. -- 測試數(shù)據(jù)
  22. INSERT INTO salgrade VALUES (1,700,1200);
  23. INSERT INTO salgrade VALUES (2,1201,1400);
  24. INSERT INTO salgrade VALUES (3,1401,2000);
  25. INSERT INTO salgrade VALUES (4,2001,3000);
  26. INSERT INTO salgrade VALUES (5,3001,9999);
  27. # 創(chuàng)建存儲過程
  28. delimiter $$
  29. create function rand_string(n INT)
  30. returns varchar(255) #該函數(shù)會返回一個(gè)字符串
  31. begin
  32. #chars_str定義一個(gè)變量 chars_str,類型是 varchar(100),默認(rèn)值’abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ’;
  33. declare chars_str varchar(100) default
  34. 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
  35. declare return_str varchar(255) default '';
  36. declare i int default 0;
  37. while i < n do
  38. set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
  39. set i = i + 1;
  40. end while;
  41. return return_str;
  42. end $$
  43. create procedure insert_emp2(in start int(10),in max_num int(10))
  44. begin
  45. declare i int default 0;
  46. #set autocommit =0 把a(bǔ)utocommit設(shè)置成0
  47. set autocommit = 0;
  48. repeat
  49. set i = i + 1;
  50. insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,floor(rand()*5+5));
  51. until i = max_num
  52. end repeat;
  53. commit;
  54. end $$
  55. delimiter ;
  56. # 調(diào)用剛剛寫好的函數(shù), 1800000條記錄,從100001號開始
  57. call insert_emp2(100001,4000000);

查詢 emp 表數(shù)據(jù),執(zhí)行 1.55 秒

  1. mysql> select * from emp;
  2. +--------+--------+----------+-----+------------+---------+--------+--------+
  3. | empno | ename | job | mgr | hiredate | sal | comm | deptno |
  4. +--------+--------+----------+-----+------------+---------+--------+--------+
  5. | 100002 | BzVfMu | SALESMAN | 1 | 2022-05-15 | 2000.00 | 400.00 | 8 |
  6. | 100003 | wcUtjQ | SALESMAN | 1 | 2022-05-15 | 2000.00 | 400.00 | 7 |
  7. | ... | ... | ... | ... | ... | ... | ... | ... |
  8. +--------+--------+----------+-----+------------+---------+--------+--------+
  9. 4000000 rows in set (1.55 sec)
  1. # 查看慢查詢?nèi)罩疚募娣盼恢?show variables like 'slow_query_log_file';

設(shè)置 long_query_time = 1,此時(shí)會生成慢查詢?nèi)罩?,文件?nèi)容如下所示

  1. # Time: 2022-05-15T02:31:37.897427Z
  2. # User@Host: root[root] @ localhost [] Id: 2
  3. # Query_time: 1.548641 Lock_time: 0.000156 Rows_sent: 4000000 Rows_examined: 4000000
  4. SET timestamp=1652581897;
  5. select * from emp;

標(biāo)簽: mysql 面試題