【宋红康 MySQL数据库 】【高级篇】【12】性能分析工具的使用
持續(xù)學習&持續(xù)更新中…
學習態(tài)度:守破離
【宋紅康 MySQL數(shù)據(jù)庫 】【高級篇】【12】性能分析工具的使用
- 數(shù)據(jù)庫服務(wù)器的優(yōu)化步驟
- 查看系統(tǒng)性能參數(shù)
- 統(tǒng)計SQL的查詢成本:last_query_cost
- 定位執(zhí)行慢的SQL:慢查詢?nèi)罩?/li>
- 開啟慢查詢?nèi)罩緟?shù)
- 查看慢查詢數(shù)目
- 案例演示
- 測試及分析
- 慢查詢?nèi)罩痉治龉ぞ?#xff1a;mysqldumpslow
- 關(guān)閉慢查詢?nèi)罩緟?shù)
- 刪除慢查詢?nèi)罩?/li>
- 查看SQL執(zhí)行成本:SHOW PROFILE
- 分析查詢語句:EXPLAIN
- 概述
- 基本語法
- 注意
- 數(shù)據(jù)準備
- EXPLAIN各列的作用
- table
- id
- select_type
- partitions (可略)
- type ☆
- possible_keys和key【possible_indexes和index】
- key_len ☆
- ref
- rows ☆
- filtered
- Extra ☆
- 索引覆蓋
- 索引條件下推
- 使用文件排序
- 小結(jié)
- EXPLAIN的進一步使用
- EXPLAIN的四種輸出格式
- 傳統(tǒng)格式
- JSON格式
- TREE格式
- 可視化輸出
- SHOW WARNINGS的使用
- 分析優(yōu)化器執(zhí)行計劃:trace
- MySQL監(jiān)控分析視圖-sys schema
- Sys schema視圖摘要
- Sys schema視圖使用場景
- 參考
數(shù)據(jù)庫服務(wù)器的優(yōu)化步驟
查看系統(tǒng)性能參數(shù)
統(tǒng)計SQL的查詢成本:last_query_cost
定位執(zhí)行慢的SQL:慢查詢?nèi)罩?/h1>
開啟慢查詢?nèi)罩緟?shù)
PS:atguigu02、atguigu05是主機名。
查看慢查詢數(shù)目
案例演示
測試及分析
慢查詢?nèi)罩痉治龉ぞ?#xff1a;mysqldumpslow
關(guān)閉慢查詢?nèi)罩緟?shù)
刪除慢查詢?nèi)罩?/h2>
查看SQL執(zhí)行成本:SHOW PROFILE
分析查詢語句:EXPLAIN
概述
-
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
-
https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
基本語法
注意
-
執(zhí)行 EXPLAIN SELECT、EXPLAIN DELETE、EXPLAIN UPDATE 語句并不會真正的執(zhí)行SQL語句,只是查看執(zhí)行計劃而已。
-
更多關(guān)注的是 EXPLAIN SELECT
數(shù)據(jù)準備
1.創(chuàng)建表
CREATE TABLE s1 (id INT AUTO_INCREMENT,key1 VARCHAR(100),key2 INT,key3 VARCHAR(100),key_part1 VARCHAR(100),key_part2 VARCHAR(100),key_part3 VARCHAR(100),common_field VARCHAR(100),PRIMARY KEY (id),INDEX idx_key1 (key1),UNIQUE INDEX idx_key2 (key2),INDEX idx_key3 (key3),INDEX idx_key_part(key_part1, key_part2, key_part3) ) ENGINE=INNODB CHARSET=utf8;CREATE TABLE s2 (id INT AUTO_INCREMENT,key1 VARCHAR(100),key2 INT,key3 VARCHAR(100),key_part1 VARCHAR(100),key_part2 VARCHAR(100),key_part3 VARCHAR(100),common_field VARCHAR(100),PRIMARY KEY (id),INDEX idx_key1 (key1),UNIQUE INDEX idx_key2 (key2),INDEX idx_key3 (key3),INDEX idx_key_part(key_part1, key_part2, key_part3) ) ENGINE=INNODB CHARSET=utf8;3.創(chuàng)建函數(shù)
SET GLOBAL log_bin_trust_function_creators=1; #創(chuàng)建函數(shù): DELIMITER // CREATE FUNCTION rand_string1(n INT) RETURNS VARCHAR(255) #該函數(shù)會返回一個字符串 BEGIN DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';DECLARE return_str VARCHAR(255) DEFAULT '';DECLARE i INT DEFAULT 0;WHILE i < n DOSET return_str =CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));SET i = i + 1;END WHILE;RETURN return_str; END // DELIMITER ;4.創(chuàng)建存儲過程并插入數(shù)據(jù)
DELIMITER // CREATE PROCEDURE insert_s1 (IN min_num INT (10),IN max_num INT (10)) BEGINDECLARE i INT DEFAULT 0;SET autocommit = 0;REPEATSET i = i + 1;INSERT INTO s1 VALUES((min_num + i),rand_string1(6),(min_num + 30 * i + 5),rand_string1(6),rand_string1(10),rand_string1(5),rand_string1(10),rand_string1(10));UNTIL i = max_numEND REPEAT;COMMIT; END // DELIMITER ;DELIMITER // CREATE PROCEDURE insert_s2 (IN min_num INT (10),IN max_num INT (10)) BEGINDECLARE i INT DEFAULT 0;SET autocommit = 0;REPEATSET i = i + 1;INSERT INTO s2 VALUES((min_num + i),rand_string1(6),(min_num + 30 * i + 5),rand_string1(6),rand_string1(10),rand_string1(5),rand_string1(10),rand_string1(10));UNTIL i = max_numEND REPEAT;COMMIT; END // DELIMITER ;#調(diào)用存儲過程 CALL insert_s1(10001,10000);CALL insert_s2(10001,10000);SELECT COUNT(*) FROM s1;SELECT COUNT(*) FROM s2;EXPLAIN各列的作用
table
EXPLAIN SELECT查出來有多少行記錄就有多少張單表(包括臨時表)
也就是說一行記錄就對應(yīng)著一張表
查詢當中有可能會出現(xiàn)一下臨時表,比如UNION。
id
在一個大的查詢語句中每個SELECT關(guān)鍵字都對應(yīng)一個唯一的id
有多少個id,就代表有多少個SELECT
查詢優(yōu)化器可能對涉及子查詢的查詢語句進行重寫,轉(zhuǎn)變?yōu)槎啾聿樵兊牟僮?#xff0c;那么自然就少了一個SELECT,因此并不是SQL語句中有多少個SELECT就有多少個SELECT
PS:一般來講,子查詢的效率不如多表連接查詢。
select_type
#3. select_type:SELECT關(guān)鍵字對應(yīng)的那個查詢的類型,確定小查詢在整個大查詢中扮演了一個什么角色# 查詢語句中不包含`UNION`或者子查詢的查詢都算作是`SIMPLE`類型EXPLAIN SELECT * FROM s1;#連接查詢也算是`SIMPLE`類型EXPLAIN SELECT * FROM s1 INNER JOIN s2;#對于包含`UNION`或者`UNION ALL`或者子查詢的大查詢來說,它是由幾個小查詢組成的,其中最左邊的那個(子查詢外邊的那個)#查詢的`select_type`值就是`PRIMARY`#對于包含`UNION`或者`UNION ALL`的大查詢來說,它是由幾個小查詢組成的,其中除了最左邊的那個小查詢#以外,其余的小查詢的`select_type`值就是`UNION`#`MySQL`選擇使用臨時表來完成`UNION`查詢的去重工作,針對該臨時表的查詢的`select_type`就是#`UNION RESULT`EXPLAIN SELECT * FROM s1 UNION SELECT * FROM s2;EXPLAIN SELECT * FROM s1 UNION ALL SELECT * FROM s2;#子查詢:#如果包含子查詢的查詢語句不能夠轉(zhuǎn)為對應(yīng)的`semi-join`的形式,并且該子查詢是不相關(guān)子查詢。#該子查詢的第一個`SELECT`關(guān)鍵字代表的那個查詢的`select_type`就是`SUBQUERY`EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2) OR key3 = 'a';#如果包含子查詢的查詢語句不能夠轉(zhuǎn)為對應(yīng)的`semi-join`的形式,并且該子查詢是相關(guān)子查詢,#則該子查詢的第一個`SELECT`關(guān)鍵字代表的那個查詢的`select_type`就是`DEPENDENT SUBQUERY`EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE s1.key2 = s2.key2) OR key3 = 'a';#注意的是,select_type為`DEPENDENT SUBQUERY`的查詢可能會被執(zhí)行多次。#在包含`UNION`或者`UNION ALL`的大查詢中,如果各個小查詢都依賴于外層查詢的話,那除了#最左邊的那個小查詢之外,其余的小查詢的`select_type`的值就是`DEPENDENT UNION`。EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2 WHERE key1 = 'a' UNION SELECT key1 FROM s1 WHERE key1 = 'b');#對于包含`派生表`的查詢,該派生表對應(yīng)的子查詢的`select_type`就是`DERIVED`EXPLAIN SELECT * FROM (SELECT key1, COUNT(*) AS c FROM s1 GROUP BY key1) AS derived_s1 WHERE c > 1;#當查詢優(yōu)化器在執(zhí)行包含子查詢的語句時,選擇將子查詢物化之后與外層查詢進行連接查詢時,#該子查詢對應(yīng)的`select_type`屬性就是`MATERIALIZED`EXPLAIN SELECT * FROM s1 WHERE key1 IN (SELECT key1 FROM s2); #子查詢被轉(zhuǎn)為了物化表partitions (可略)
type ☆
# 5. type:針對單表的訪問方法#當表中`只有一條記錄`并且該表使用的存儲引擎的統(tǒng)計數(shù)據(jù)是精確的【MyISAM表中有一個變量記錄了count(*)的值】,比如MyISAM、Memory,#那么對該表的訪問方法就是`system`。CREATE TABLE t(i INT) ENGINE=MYISAM;INSERT INTO t VALUES(1);EXPLAIN SELECT * FROM t;#換成InnoDBCREATE TABLE tt(i INT) ENGINE=INNODB;INSERT INTO tt VALUES(1);EXPLAIN SELECT * FROM tt;#當我們根據(jù)主鍵或者唯一二級索引列與常數(shù)進行等值匹配時,對單表的訪問方法就是`const`EXPLAIN SELECT * FROM s1 WHERE id = 10005;EXPLAIN SELECT * FROM s1 WHERE key2 = 10066;# 不是一個類型的話就需要進行隱式轉(zhuǎn)換,就不會使用索引了。EXPLAIN SELECT * FROM s1 WHERE key3 = 10066;EXPLAIN SELECT * FROM s1 WHERE key3 = '10066';#在連接查詢時,如果被驅(qū)動表是通過主鍵或者唯一二級索引列等值匹配的方式進行訪問的#(如果該主鍵或者唯一二級索引是聯(lián)合索引的話,所有的索引列都必須進行等值比較),則#對該被驅(qū)動表的訪問方法就是`eq_ref`EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;#當通過普通的二級索引列與常量進行等值匹配時來查詢某個表,那么對該表的訪問方法就可能是`ref`EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';#當對普通二級索引進行等值匹配查詢,該索引列的值也可以是`NULL`值時,那么對該表的訪問方法#就可能是`ref_or_null`EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key1 IS NULL;#單表訪問方法時在某些場景下可以使用`Intersection`、`Union`、#`Sort-Union`這三種索引合并的方式來執(zhí)行查詢# type為index_merge【where必須使用OR關(guān)鍵字】EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key3 = 'a';#`unique_subquery`是針對在一些包含`IN`子查詢的查詢語句中,如果查詢優(yōu)化器決定將`IN`子查詢#轉(zhuǎn)換為`EXISTS`子查詢,而且子查詢可以使用到主鍵進行等值匹配的話,那么該子查詢執(zhí)行計劃的`type`#列的值就是`unique_subquery`EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 WHERE s1.key1 = s2.key1) OR key3 = 'a';#如果使用索引獲取某些`范圍區(qū)間`的記錄,那么就可能使用到`range`訪問方法EXPLAIN SELECT * FROM s1 WHERE key1 IN ('a', 'b', 'c');#同上EXPLAIN SELECT * FROM s1 WHERE key1 > 'a' AND key1 < 'b';#當我們可以使用索引覆蓋,但需要掃描全部的索引記錄時,該表的訪問方法就是`index`# 覆蓋索引(索引覆蓋):查詢語句的WHERE條件中使用的是二級索引,并且只查詢索引列的值,那么就不需要進行回表操作。EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = 'a';#最熟悉的全表掃描EXPLAIN SELECT * FROM s1;possible_keys和key【possible_indexes和index】
possible_keys和key:可能用到的索引 和 實際上使用的索引
#6. possible_keys和key:可能用到的索引 和 實際上使用的索引EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key3 = 'a';key_len ☆
key_len:實際使用到的索引長度(即:字節(jié)數(shù)),主要針對于聯(lián)合索引
幫你檢查是否充分的利用上了索引,值越大越好,有一定的參考意義。
ref
當使用索引列等值查詢時,與索引列進行等值匹配的對象信息。
# 8. ref:當使用索引列等值查詢時,與索引列進行等值匹配的對象信息。#比如只是一個常數(shù)或者是某個列。EXPLAIN SELECT * FROM s1 WHERE key1 = 'a';EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id;EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s2.key1 = UPPER(s1.key1);rows ☆
預(yù)估的需要讀取的記錄條數(shù),值越小越好
# 9. rows:預(yù)估的需要讀取的記錄條數(shù)# `值越小越好`EXPLAIN SELECT * FROM s1 WHERE key1 > 'z';filtered
某個表經(jīng)過搜索條件過濾后剩余記錄條數(shù)的百分比
# 10. filtered: 某個表經(jīng)過搜索條件過濾后剩余記錄條數(shù)的百分比#如果使用的是索引執(zhí)行的單表掃描,那么計算時需要估計出滿足除使用#到對應(yīng)索引的搜索條件外的其他搜索條件的記錄有多少條。EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND common_field = 'a';#對于單表查詢來說,這個filtered列的值沒什么意義,我們`更關(guān)注在連接查詢#中驅(qū)動表對應(yīng)的執(zhí)行計劃記錄的filtered值`,它決定了被驅(qū)動表要執(zhí)行的次數(shù)(即:rows * filtered)EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key1 WHERE s1.common_field = 'a';Extra ☆
索引覆蓋
索引覆蓋:查詢語句的WHERE條件中使用的是二級索引,并且只查詢索引列的值,那么就不需要進行回表操作。
索引條件下推
#11. Extra:一些額外的信息#更準確的理解MySQL到底將如何執(zhí)行給定的查詢語句#當查詢語句的沒有`FROM`子句時將會提示該額外信息EXPLAIN SELECT 1;#查詢語句的`WHERE`子句永遠為`FALSE`時將會提示該額外信息EXPLAIN SELECT * FROM s1 WHERE 1 != 1;#當我們使用全表掃描來執(zhí)行對某個表的查詢,并且該語句的`WHERE`#子句中有針對該表的搜索條件時,在`Extra`列中會提示上述額外信息。EXPLAIN SELECT * FROM s1 WHERE common_field = 'a';#當使用索引訪問來執(zhí)行對某個表的查詢,并且該語句的`WHERE`子句中#有除了該索引包含的列之外的其他搜索條件時,在`Extra`列中也會提示上述額外信息。EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' AND common_field = 'a';#當查詢列表處有`MIN`或者`MAX`聚合函數(shù),但是并沒有符合`WHERE`子句中#的搜索條件的記錄時,將會提示該額外信息EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = 'abcdefg';EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = 'NlPros'; #NlPros 是 s1表中key1字段真實存在的數(shù)據(jù)#select * from s1 limit 10;# 覆蓋索引(索引覆蓋):查詢語句的WHERE條件中使用的是二級索引,并且只查詢索引列的值,那么就不需要進行回表操作。#當我們的查詢列表以及搜索條件中只包含屬于某個索引的列,也就是在可以#使用覆蓋索引的情況下,在`Extra`列將會提示該額外信息。比方說下邊這個查詢中只#需要用到`idx_key1`而不需要回表操作:EXPLAIN SELECT key1,id FROM s1 WHERE key1 = 'a';#有些搜索條件中雖然出現(xiàn)了索引列,但卻不能使用到索引#理解索引條件下推EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key1 LIKE '%a';#在連接查詢執(zhí)行過程中,當被驅(qū)動表不能有效的利用索引加快訪問速度,MySQL一般會為#其分配一塊名叫`join buffer`的內(nèi)存塊來加快查詢速度,也就是我們所講的`基于塊的嵌套循環(huán)算法`#見課件說明EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;#當我們使用左(外)連接時,如果`WHERE`子句中包含要求被驅(qū)動表的某個列等于`NULL`值的搜索條件,#而且那個列又是不允許存儲`NULL`值的,那么在該表的執(zhí)行計劃的Extra列就會提示`Not exists`額外信息EXPLAIN SELECT * FROM s1 LEFT JOIN s2 ON s1.key1 = s2.key1 WHERE s2.id IS NULL;#如果執(zhí)行計劃的`Extra`列出現(xiàn)了`Using intersect(...)`提示,說明準備使用`Intersect`索引#合并的方式執(zhí)行查詢,括號中的`...`表示需要進行索引合并的索引名稱;#如果出現(xiàn)了`Using union(...)`提示,說明準備使用`Union`索引合并的方式執(zhí)行查詢;#出現(xiàn)了`Using sort_union(...)`提示,說明準備使用`Sort-Union`索引合并的方式執(zhí)行查詢。EXPLAIN SELECT * FROM s1 WHERE key1 = 'a' OR key3 = 'a';#當我們的`LIMIT`子句的參數(shù)為`0`時,表示壓根兒不打算從表中讀出任何記錄,將會提示該額外信息EXPLAIN SELECT * FROM s1 LIMIT 0;#有一些情況下對結(jié)果集中的記錄進行排序是可以使用到索引的。#比如:EXPLAIN SELECT * FROM s1 ORDER BY key1 LIMIT 10;#很多情況下排序操作無法使用到索引,只能在內(nèi)存中(記錄較少的時候)或者磁盤中(記錄較多的時候)#進行排序,MySQL把這種在內(nèi)存中或者磁盤上進行排序的方式統(tǒng)稱為文件排序(英文名:`filesort`)。#如果某個查詢需要使用文件排序的方式執(zhí)行查詢,就會在執(zhí)行計劃的`Extra`列中顯示`Using filesort`提示EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;#在許多查詢的執(zhí)行過程中,MySQL可能會借助臨時表來完成一些功能,比如去重、排序之類的,比如我們#在執(zhí)行許多包含`DISTINCT`、`GROUP BY`、`UNION`等子句的查詢過程中,如果不能有效利用索引來完成#查詢,MySQL很有可能尋求通過建立內(nèi)部的臨時表來執(zhí)行查詢。如果查詢中使用到了內(nèi)部的臨時表,在執(zhí)行#計劃的`Extra`列將會顯示`Using temporary`提示EXPLAIN SELECT DISTINCT common_field FROM s1;#EXPLAIN SELECT DISTINCT key1 FROM s1;#同上。EXPLAIN SELECT common_field, COUNT(*) AS amount FROM s1 GROUP BY common_field;#執(zhí)行計劃中出現(xiàn)`Using temporary`并不是一個好的征兆,因為建立與維護臨時表要付出很大成本的,所以#我們`最好能使用索引來替代掉使用臨時表`。比如:掃描指定的索引idx_key1即可EXPLAIN SELECT key1, COUNT(*) AS amount FROM s1 GROUP BY key1;使用文件排序
小結(jié)
EXPLAIN的進一步使用
EXPLAIN的四種輸出格式
傳統(tǒng)格式
JSON格式
#json格式的explain EXPLAIN FORMAT=JSON SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key2 WHERE s1.common_field = 'a';
TREE格式
可視化輸出
SHOW WARNINGS的使用
分析優(yōu)化器執(zhí)行計劃:trace
MySQL監(jiān)控分析視圖-sys schema
Sys schema視圖摘要
Sys schema視圖使用場景
參考
尚硅谷宋紅康: MySQL數(shù)據(jù)庫(入門到高級,菜鳥到大牛).
本文完,感謝您的關(guān)注支持!
總結(jié)
以上是生活随笔為你收集整理的【宋红康 MySQL数据库 】【高级篇】【12】性能分析工具的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读刘文鹏之《古代埃及史》
- 下一篇: linux cmake编译源码,linu