MySQL 性能分析備忘錄

[TOC]

最後修改時間: 2019年10月21日15:08:59

救急

show full processlist

查看當前線程處理情況, 確認當前有哪些語句在執行, 執行情況如何.

特別注意執行時間長的, 如果確定有問題, 那麼可以使用 kill {id} 幹掉該連接

show full processlist 等價於以下語句

select id, db, user, host, command, time, state, info
from information_schema.processlist
order by time desc;

注意:

  • show processlist時, root賬號可以看到所有賬號的連接, 如果是普通賬號則只能看到自己的連接.
  • 如果顯示長度太長看的很亂, 可以使用 \G, 即 show full processlist\G , 來將顯示結果縱向輸出, 方便查看.
擴展.

\g 等價於分號

\G 是將顯示的表格以縱向輸出, 方便查看.

Slow Query Log 慢查詢日誌

慢查詢日誌用於記錄執行時間超過指定閥值的SQL命令.

確認開啓情況

mysql> show variables like 'slow_query_log%';
+---------------------+------------------------------------------------+
| Variable_name       | Value                                          |
+---------------------+------------------------------------------------+
| slow_query_log      | ON                                             |
| slow_query_log_file | C:\laragon\data\mysql\DESKTOP-C1GGBS1-slow.log |
+---------------------+------------------------------------------------+

mysql> show variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+

開啓方式

配置文件

############### 慢查詢日誌 ################
# 打開慢查詢日誌
slow_query_log=1
# 日誌記錄位置
log_output=file
# 慢查詢日誌記錄文件
slow_query_log_file=/var/run/mysqld/mysqld-slow.log
# 慢查詢時間閥值
long_query_time=10

命令方式(mysqld實例重啓後失效)

-- 必須全局開啓慢查詢日誌記錄
set global slow_query_log=1;

-- 設置慢查詢時間閥值
set global long_query_time=1;

如果想要分析一些語句的執行, 則可以考慮將當前Session的慢查詢時間閥值設爲0

set long_query_time=0;

注意

當數據庫被拖垮時(高負載), 任何簡單的語句都可能執行超時, 此時的慢查詢日誌能提供的幫助就有限了.

慢查詢日誌分析工具

mysqldumpslow

在實際生產環境中,如果要手工分析日誌,查找、分析SQL,顯然是個體力活,MySQL提供了日誌分析工具mysqldumpslow

# 分析慢日誌
mysqldumpslow -a -n 50 -s c /var/run/mysqld/mysqld-slow.log

# 參數說明
--verbose    版本
--debug      調試
--help       幫助
 
-v           版本
-d           調試模式
-s ORDER     排序方式, 默認是 'at'
             what to sort by (al, at, ar, c, l, r, t), 'at' is default
              al: average lock time 平均鎖定時間
              ar: average rows sent 平均返回記錄數
              at: average query time 平均查詢時間
               c: count 訪問計數
               l: lock time 鎖定時間
               r: rows sent 返回記錄
               t: query time 查詢時間
-r           反轉順序,默認文件倒序拍。reverse the sort order (largest last instead of first)
-t NUM       顯示前N條
-a           不要將SQL中數字轉換成N,字符串轉換成S。don't abstract all numbers to N and strings to 'S'
-n NUM       abstract numbers with at least n digits within names
-g PATTERN   正則匹配;grep: only consider stmts that include this string
-h HOSTNAME  mysql機器名或者IP;hostname of db server for *-slow.log filename (can be wildcard),
             default is '*', i.e. match all
-i NAME      name of server instance (if using mysql.server startup script)
-l           總時間中不減去鎖定時間;don't subtract lock time from total time

示例

得到返回記錄集最多的10個SQL。
mysqldumpslow -s r -t 10 /database/mysql/mysql06_slow.log
 
得到訪問次數最多的10個SQL
mysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log

得到按照時間排序的前10條裏面含有左連接的查詢語句。
mysqldumpslow -s t -t 10 -g “left join” /database/mysql/mysql06_slow.log
 
另外建議在使用這些命令時結合 | 和more 使用 ,否則有可能出現刷屏的情況。
mysqldumpslow -s r -t 20 /mysqldata/mysql/mysql06-slow.log | more

SQL Explain

對於慢查詢日誌中執行慢的語句分析其 SQL語句的執行計劃

EXPLAIN 可以幫助瞭解:

  • 數據表的讀取順序
  • SELECT子句的類型
  • 數據表的訪問類型
  • 可使用的索引 possible_keys
  • 實際使用的索引 key
  • 使用的索引長度 ken_len
  • 上一個表的連接匹配條件
  • 被優化器查詢的行的數量
  • 額外的信息(如使用使用外部排序, 是否使用臨時表)

舉例

1559124811057.png

EXPLAIN 結果列分析

<u>字段 id</u>

SQL 執行順序是根據

  • id從大到小執行
  • id相同時按照順序從上往下執行.

<u>字段 select_type(查詢類型)</u>

查詢類型 說明
SIMPLE 簡單查詢
不包含UNION查詢或子查詢
PRIMARY 最外層查詢
查詢中若 包含任何複雜的子部分,最外層查詢則被標記爲PRIMARY
SUBQUERY 子查詢
在 SELECT 或 WHERE 中包含了子查詢
DEPENDENT SUBQUERY !!! 子查詢, 但依賴於外層查詢的結果
注意確認, 避免大表驅動小表
DERIVED 子查詢
在 FROM 列表中包含的子查詢被標記爲 DERIVED(衍生)
UNION 聯合
UNION 若第二個SELECT出現在UNION之後,則被標記爲UNION
UNION RESULT 使用聯合的結果
從UNION表獲取結果的SELECT
關於UNION, 網上有寫以下這段, 但我個人不理解

UNION 若第二個SELECT出現在UNION之後,則被標記爲UNION:若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲:DERIVED


<u>字段 table(數據表)</u>

訪問的數據表


<u>字段 partitions(分區)</u>

匹配的分區


<u>字段 type(訪問方式)</u>

查詢時的訪問方式, 性能:all < index < range < index_merge < ref < eq_ref < system/const

一般來說至少需要保證訪問方式是 range, 最好是 ref 級別.

訪問方式 說明
ALL 全表掃描,對於數據表從頭到尾找一遍
select * from tb1;
特別的:如果有limit限制,則找到之後就不在繼續向下掃描
select * from tb1 where email = '[email protected]'
select * from tb1 where email = '[email protected]' limit 1;
雖然上述兩個語句都會進行全表掃描,第二句使用了limit,則找到一個後就不再繼續掃描。
INDEX 全索引掃描,對索引從頭到尾找一遍
因爲非主鍵索引樹比較小, 所以會比 ALL 更快
RANGE 對索引列進行範圍查找
通常是在索引樹上快速定位到某一索引項, 再向左/右遍歷.
INDEX_MERGE 合併索引,使用多個單列索引搜索, 最後結果取交集或並集
比如使用了UNION 且單獨用到了兩個索引.
REF 使用索引快速定位(根據索引查找一個或多個值), 該索引是 普通索引唯一索引的部分前綴
EQ_REF 使用主鍵索引或唯一索引快速定位
通常出現在多表的join查詢, 連接時使用primary key 或 unique 索引(都只能匹配到一行記錄)
CONST 通過主鍵或唯一索引精確查找到一行
常量
表最多有一個匹配行(主鍵或唯一索引),因爲僅有一行,在這行的列值可被優化器剩餘部分認爲是常數,const表很快,因爲它們只讀取一次
SYSTEM 系統
表僅有一行, 這是const聯接類型的一個特例, 可以忽略這種情況。

Q. ALL 和 INDEX 的區別

A. 兩個都是全索引掃描, 不同的是 ALL 是對主鍵索引掃描, INDEX 是對非主鍵索引掃描.

這裏要理解, 所謂的全表掃描指的是對主鍵索引掃描.

Q. EQ_REFCONST 的區別

A. 相同點都是使用主鍵/唯一索引精確查找到行記錄. 不同點在於:

  • CONST 查詢條件通常是 索引列 = 具體常量值
  • EQ_REF 通常是在多表關聯查詢時作爲連接條件使用.

<u>字段 possible_keys(候選索引)</u>


<u>字段 key(實際使用的索引)</u>

如果是合併索引(INDEX_MERGE), 則此處可能存在超過1個的key


<u>字段 key_len(使用索引的實際長度)</u>

該字段可以評估組合索引是否完全被使用或僅僅是最左前綴被用到.

該字段顯示的值爲索引字段的最大可能長度, 並非實際使用長度.(即 key_len 是根據表定義計算, 而非表內檢索)

計算規則

字段類型 計算方式
字符串 char(n) n字節長度
varchar(n) 若是utf8編碼, 則是 n3 + 2 字節
如果是 utf8mb4 編碼, 則是 4
n + 2 字節.
數值 tinyint 1字節
smallint 2字節
mediumint 3字節
int 4字節
bigint 8字節
時間 date 3字節
timestamp 4字節
datetime 8字節

如果對應索引字段允許爲 null, 則還要額外消耗1個字節來存儲 NULL.


<u>字段 ref</u>

表示索引的查找條件, 可能是常量(const) 或 聯合查詢中另一張表的某個字段.


<u>字段 row(掃描行數)</u>

估算的需要掃描的行數, 注意是估算的.

在某些情況下若索引統計信息偏差較大, 則此處的預估掃描行數也會過大, 導致影響查詢計劃的選擇.

可以使用 SHOW INDEX FROM 表名 來查看索引統計信息

可以使用 ANYLYSIS TABLE 表名來重新統計索引信息.


<u>字段 filtered</u>


<u>字段 Extra(額外信息)</u>

該列包含MySQL解決查詢的詳細信息

說明
Using filesort mysql無法依靠索引直接獲取有序記錄, 而是對結果進行額外排序.
mysql有兩種文件排序算法,這兩種排序方式都可以在內存或者磁盤上完成
explain不會告訴你mysql將使用哪一種文件排序
也不會告訴你排序會在內存裏還是磁盤上完成。
Using index 使用覆蓋索引,以避免訪問表。不要把覆蓋索引和index訪問類型弄混了。
Using index condition 索引下推優化, 5.6新增特性
Using temporary 意味着mysql在對查詢結果排序時會使用一個臨時表
Using where 使用了 where 過濾
這意味着mysql服務器將在存儲引擎檢索行後再進行過濾
許多where條件裏涉及索引中的列,當(並且如果)它讀取索引時,就能被存儲引擎檢驗
因此不是所有帶where子句的查詢都會顯示“Using where”。
有時“Using where”的出現就是一個暗示:查詢可受益於不同的索引。
Range checked for each record(index map: N) 這個意味着沒有好用的索引,新的索引將在聯接的每一行上重新估算,N是顯示在possible_keys列中索引的位圖,並且是冗餘的。
using join buffer 在表聯結時, 使用了連接緩存

Profiling

寫在最前: SHOW PROFILE 命令將被棄用, 注意, 僅僅是 SHOW PROFILE命令棄用.

替代方案是從 information_schema 中的profiling數據表進行查看, 可參數鏈接:

SHOW PROFILE 命令方式(舊)

查看語句執行的時間在各個步驟的開銷

show profile 分析SQL性能工具(檢測數據存在於臨時表中)

  • 在會話級別開啓profile SET profiling=1;
  • 發送sql
  • 查看profile的資源開銷結果

    • show profiles 查看所有的分析結果(會有一個數量上限)
    • show profile 查看最後一條執行語句的分析結果
    • show profile for query <id> 查看指定執行語句的詳細分析結果
    • show profile cpu, block io for query <id> 查看詳細信息, 且包含 cpu, block.io 執行時間
  • 關閉profile

這一部分更詳細的可以參考如:

information_schema .profiling

待用到時補充.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章