分析SQL的執行過程


官方文檔:Understanding the Query Execution Plan

SQL優化的一般步驟:先查詢mysql數據庫運行狀況,然后定位慢查詢,再分析sql的執行過程,最后根據情況采取相應的優化措施。

一、定位慢查詢

1.使用show status查詢數據庫的運行狀況

//顯示數據庫運行狀態
SHOW STATUS
//顯示數據庫運行總時間
SHOW STATUS LIKE 'uptime'
//顯示連接的次數
SHOW STATUS LIKE 'connections'
//顯示執行CRUD的次數
SHOW STATUS LIKE 'com_select'
SHOW STATUS LIKE 'com_insert'
SHOW STATUS LIKE 'com_update'
SHOW STATUS LIKE 'com_delete'

2.定位慢查詢sql

我們可以通過mysql來記錄慢查詢,一旦有sql執行時間超過了設置的慢查詢時間,就會被記錄到慢查詢日志中。這樣我們就可以從慢查詢日志中定位慢查詢sql,然后進行分析優化。

查看慢查詢相關信息

//顯示慢查詢次數
SHOW STATUS LIKE 'slow_queries'
//顯示慢查詢時間,默認為10s
SHOW VARIABLES LIKE 'long_query_time'

mysql的慢查詢默認是關閉的,可以通過修改配置文件或通過命令來開啟。

①修改配置文件方式

Linux下修改my.cnf,Windows下修改my.ini。修改后需要重啟mysql才會生效。

#開啟慢查詢
slow-query-log=1
#慢查詢的文件路徑
slow_query_log_file="D:/Program Files/MySQL/Log/mysql-slow.log"
#慢查詢時間。默認為10秒
long_query_time=10

②命令方式

也可以使用命令來修改。

【session級別】
#開啟慢查詢
SET slow_query_log='ON';

#設置慢查詢日志存放位置
SET slow_query_log_file='/usr/local/mysql/data/slow.log';

#設置慢查詢時間
SET long_query_time=3

【global級別】
SET global slow_query_log='ON';
SET global slow_query_log_file='/usr/local/mysql/data/slow.log';
SET global long_query_time=3

3.分析慢查詢

在實際生產環境中,可能因為開發寫了不正確的SQL語句,索引優化的不好,或其他查詢操作而導致數據庫整體性能下降。我們只需要分析一下慢查詢日志就會知道問題出在哪。

//查看是否啟用慢日志記錄和狀態
show variables like "%slow%"

如果慢查詢日志中記錄內容較多,則可以使用Mysql自帶的慢查詢日志分析工具mysqldumpslow工具來對慢查詢日志進行分類匯總。該工具位於/mysql/bin目錄下。mysqldumpslow將會自動將文本完全一致但變量不同的SQL語句視為同一個語句進行統計,變量值用N來代替。

mysqldumpslow -s r -t 10 /data/dbdata/frem-slow.log

 

 

另外,show processlist也是一個常用命令。

官方文檔:13.7.5.29 SHOW PROCESSLIST Statement

show full processlist

show processlist 是顯示用戶正在運行的線程,需要注意的是,除了 root 用戶能看到所有正在運行的線程外,其他用戶都只能看到自己正在運行的線程,看不到其它用戶正在運行的線程。除非單獨個這個用戶賦予了PROCESS 權限。

可以參考:show processlist 詳解

 

二、使用explain分析sql執行過程

官方文檔:Optimizing Queries with EXPLAIN

mysql會將慢查詢記錄到慢查詢日志中,這時我們就可以針對這些慢查詢的sql進行分析和優化,需要用到explain命令。

explain [要分析的sql]

分析結果中有如下幾列:

+----+-------------+---------+------+---------------+------+---------+------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+-------+

下面介紹各列的含義。可以參考官方文檔說明:Explain Output Colums

id

表示select查詢序列號。id值越大,越優先執行。如果id相同,執行順序由上至下;

       

select_type

表示查詢操作的類型。主要用於區分普通查詢、子查詢、聯合查詢等幾種查詢情況。有這些取值:simple,primary,subquery,derived,union,union result

①simple:表示簡單查詢,只有一個select操作,即不使用連接和union。

#只有一個select操作,所以都是簡單查詢

select id from emp;

select id from emp join dept on emp.dept_id=dept.id;

②primary:表示主查詢。子查詢語句中的最外層select,或union操作的第一個select。

#子查詢形式:第一個select操作為primary
select * from app_school where id = (select id from app_school where id=100);

#union形式:第一個select操作為primary
select * from app_school where id=100
union
select * from app_school where id=101;

③subquery:表示子查詢。子查詢語句中的內層select。

#第二個select操作為subquery
select * from app_school where id = (select id from app_school where id=100);

④derived:表示FROM后跟着的select查詢,會被標記為derived(導出表/衍生表)。

#第二個select操作為derived
select * from (select id from app_school) t;

⑤union:表示UNION操作后面的select查詢。

#第二個select操作為union
select * from app_school where id=100
union
select * from app_school where id=101;

⑥union result:表示獲取UNION最后結果的查詢。

#第一個select操作為primary
#第二個select操作為union
#獲取最終結果的操作為union result
select * from app_school where id=100
union
select * from app_school where id=101;

table

表示查詢用到的表。

type

表示找到匹配行用到的訪問類型。最為常見的類型有system,const,eq_ref,ref,range,index,All按照性能從高到低順序如下:NULL-->system-->const-->eq-ref-->ref-->range-->index-->All 。一般來說,要讓查詢至少達到range級別,最好能達到ref級別。

NULL:不用訪問表或索引,就可直接得出結果。

system:該表是最多僅有一行的系統表(這是const類型的一個特例)。系統表中的數據通常已經加載到了內存中,所以不需要磁盤IO。
例子1:查詢系統表

例子2:內層嵌套(const)返回了一個臨時表,外層嵌套從臨時表中查詢,其掃描類型也是system,也不需要磁盤IO。

const:最多只有一個匹配行,所以該行中的其它列的值可以當作常量來處理。例如,根據主鍵primary key或唯一索引unique index進行查詢。簡單地說const就是直接按主鍵或唯一鍵取值。例如在②中介紹system時的舉例中user表的訪問類型就是const,其通過主鍵來取值。

eq_ref:使用唯一索引,對於每個索引鍵值,表中只有一條記錄匹配。簡單說,就是多表連接中使用primary key或unique index作為關聯條件。

注意const和eq_ref的區別:簡單地說是const是直接按主鍵或唯一鍵讀取,eq_ref用於聯表查詢的情況,按聯表的主鍵或唯一鍵聯合查詢。

ref:使用非唯一索引,或唯一索引的前綴掃描,返回匹配某個單獨值的所有行(可能匹配多個行)。

ref還經常出現在join操作中

ref_or_null:與ref類似,區別在於條件中包含對NULL的查詢。

index_merge:索引合並優化。

unique_subquery:in的后面是一個查詢主鍵字段的子查詢。

index_subquery:與unique subquery類似,區別在於in的后面是查詢非唯一索引字段的子查詢。

⑩range:只檢索指定范圍的行,使用一個索引來選擇行。常見於<,<=,>,>=,between或者IN操作符。
             key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。

11.index:索引全掃描。遍歷整個索引來查詢匹配的行。

12.ALL:全表掃描,性能最差。

possible_keys和key

possible_keys表示查詢時可能使用到的索引,而key表示實際使用的索引

key_len

表示使用到的索引字段的長度

ref

表示該表的索引字段關聯了哪張表的哪個字段

rows

表示掃描行的數量

Extra

表示執行情況的說明和描述。包含不適合在其它列中顯示但對執行計划非常重要的額外信息。

可以參考:MySQL中explain執行計划中額外信息字段(Extra)詳解

記錄幾個重要的:

Using index :使用覆蓋索引的時候就會出現

Using where:在查找使用索引的情況下,需要回表去查詢所需的數據        表示Mysql將對storage engine提取的結果進行過濾,過濾條件字段無索引;

Using index condition:查找使用了索引,但是需要回表查詢數據               會先條件過濾索引,過濾完索引后找到所有符合索引條件的數據行,隨后用 WHERE 子句中的其他條件去過濾這些數據行;

Using index & using where:查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢數據

Using filesort:使用了文件排序。當查詢語句包含ORDER BY時,如果無法使用索引來完成排序,則需要進行額外的排序操作。

Using temporary:使用臨時表來保存中間結果,

三、使用show profile分析sql

官方文檔:SHOW PROFILE StatementSHOW PROFILES Statement

有時僅通過explain分析執行計划並不能很快地定位SQL的問題,這時就可以選擇profile聯合分析。Mysql從5.0.37開始增加了對show profiles和show profile語句的支持。

默認profile是關閉的,可以通過set開啟session級別的profiling。

//查看是否支持profile
SELECT @@have_profiling
//開啟profile(session級別)
set profiling=1;

①執行select語句
②show profiles,查詢該sql語句的Query ID.
③通過show profile for query語句能看到執行中線程的每個狀態和消耗的時間。

show profile for query [上面的query id]

四、通過trace分析優化器如何選擇執行計划

官方文檔:Chapter 8 Tracing the Optimizer

Mysql5.6提供了對sql的跟蹤trace,通過trace文件能夠進一步了解為什么優化器選擇A執行計划而不選擇B執行計划,幫助我們更好地理解優化器的行為。

下面是典型的使用方式:

# 開啟trace(默認關閉),設置json格式
SET OPTIMIZER_TRACE="enabled=on",END_MARKERS_IN_JSON=on;
//設置內存,避免解析過程中因為默認內存過小而不能夠完整顯示。
SET OPTIMIZER_TRACE_MAX_MEM_SIZE=1000000;

#執行sql
SELECT ...; # your query here

#檢查INFORMATION_SCHEMA.OPTIMIZER_TRACE就知道mysql是如何執行sql的了
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;

# 完成后,關閉trace
SET optimizer_trace="enabled=off";

最后會輸出一個跟蹤文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM