35 張圖帶你 MySQL 調優

一般傳統互聯網公司很少接觸到 SQL 優化問題,其原因是數據量小,大部分廠商的數據庫性能能夠滿足日常的業務需求,所以不需要進行 SQL 優化,但是隨着應用程序的不斷變大,數據量的激增,數據庫自身的性能跟不上了,此時就需要從 SQL 自身角度來進行優化,這也是我們這篇文章所討論的。

SQL 優化步驟

當面對一個需要優化的 SQL 時,我們有哪幾種排查思路呢?

通過 show status 命令瞭解 SQL 執行次數

首先,我們可以使用 show status 命令查看服務器狀態信息。show status 命令會顯示每個服務器變量 variable_name 和 value,狀態變量是隻讀的。如果使用 SQL 命令,可以使用 like 或者 where 條件來限制結果。like 可以對變量名做標準模式匹配。

圖我沒有截全,下面還有很多變量,讀者可以自己嘗試一下。也可以在操作系統上使用 mysqladmin extended-status 命令來獲取這些消息。

但是我執行 mysqladmin extended-status 後,出現這個錯誤。

應該是我沒有輸入密碼的原因,使用 mysqladmin -P3306 -uroot -p -h127.0.0.1 -r -i 1 extended-status 後,問題解決。

這裏需要注意一下 show status 命令中可以添加統計結果的級別,這個級別有兩個

如果不指定統計結果級別的話,默認使用 session 級別。

對於 show status 查詢出來的統計結果,有兩類參數需要注意下,一類是以 Com_ 爲開頭的參數,一類是以 Innodb_ 爲開頭的參數。

下面是 Com_ 爲開頭的參數,參數很多,我同樣沒有截全。

Com_xxx 表示的是每個 xxx 語句執行的次數,我們通常關心的是 select 、insert 、update、delete 語句的執行次數,即

以 Innodb_ 爲開頭的參數主要有

通過上面這些參數執行結果的統計,我們能夠大致瞭解到當前數據庫是以更新(包括插入、刪除)爲主還是查詢爲主。

除此之外,還有一些其他參數用於瞭解數據庫的基本情況。

下面這個博客彙總了幾乎所有 show status 的參數,可以當作參考手冊。

https://blog.csdn.net/ayay_870621/article/details/88633092

定位執行效率較低的 SQL

定位執行效率比較慢的 SQL 語句,一般有兩種方式

MySQL 中提供了一個慢查詢的日誌記錄功能,可以把查詢 SQL 語句時間大於多少秒的語句寫入慢查詢日誌,日常維護中可以通過慢查詢日誌的記錄信息快速準確地判斷問題所在。用 --log-slow-queries 選項啓動時,mysqld 會寫一個包含所有執行時間超過 long_query_time 秒的 SQL 語句的日誌文件,通過查看這個日誌文件定位效率較低的 SQL 。

比如我們可以在 my.cnf 中添加如下代碼,然後退出重啓 MySQL。

通常我們設置最長的查詢時間是 2 秒,表示查詢時間超過 2 秒就記錄了,通常情況下 2 秒就夠了,然而對於很多 WEB 應用來說,2 秒時間還是比較長的。

也可以通過命令來開啓:

我們先查詢 MySQL 慢查詢日誌是否開啓

啓用慢查詢日誌

然後再次查詢慢查詢是否開啓

如圖所示,我們已經開啓了慢查詢日誌。

慢查詢日誌會在查詢結束以後才記錄,所以在應用反應執行效率出現問題的時候慢查詢日誌並不能定位問題,此時應該使用 show processlist 命令查看當前 MySQL 正在進行的線程。包括線程的狀態、是否鎖表等,可以實時的查看 SQL 執行情況。同樣,使用 mysqladmin processlist 語句也能得到此信息。

下面就來解釋一下各個字段對應的概念

State 列非常重要,關於這個列的內容比較多,讀者可以參考一下這篇文章

https://blog.csdn.net/weixin_34357436/article/details/91768402

這裏面涉及線程的狀態、是否鎖表等選項,可以實時的查看 SQL 的執行情況,同時對一些鎖表進行優化。

通過 EXPLAIN 命令分析 SQL 的執行計劃

通過以上步驟查詢到效率低的 SQL 語句後,可以通過 EXPLAIN 或者 DESC 命令獲取 MySQL 如何執行 SELECT 語句的信息,包括在 SELECT 語句執行過程中表如何連接和連接的順序。

比如我們使用下面這條 SQL 語句來分析一下執行計劃

explain select * from test1;

上表中涉及內容如下

PRIMARY ,查詢中最外層的 SELECT(如兩表做 UNION 或者存在子查詢的外層的表操作爲 PRIMARY,內層的操作爲 UNION),比如下面這段子查詢。

UNION,在 UNION 操作中,查詢中處於內層的 SELECT(內層的 SELECT 語句與外層的 SELECT 語句沒有依賴關係時)。

SUBQUERY:子查詢中首個 SELECT(如果有多個子查詢存在),如我們上面的查詢語句,子查詢第一個是 sr(sys_role)表,所以它的 select_type 是 SUBQUERY。

上面就是 type 內容的大致解釋,關於 type 我們經常會在 SQL 調優的環節使用 explain 分析其類型,然後改進查詢方式,越靠近 system 其查詢效率越高,越靠近 all 其查詢效率越低。

通過上面的分析,我們可以大致確定 SQL 效率低的原因,一種非常有效的提升 SQL 查詢效率的方式就是使用索引,接下來我會講解一下如何使用索引提高查詢效率。

索引

索引是數據庫優化中最常用也是最重要的手段,通過使用不同的索引可以解決大多數 SQL 性能問題,也是面試經常會問到的優化方式,圍繞着索引,面試官能讓你造出火箭來,所以總結一點就是索引非常非常重!要!不只是使用,你還要懂其原!理!

索引介紹

索引的目的就是用於快速查找某一列的數據,對相關數據列使用索引能夠大大提高查詢操作的性能。不使用索引,MySQL 必須從第一條記錄開始讀完整個表,直到找出相關的行,表越大查詢數據所花費的時間就越多。如果表中查詢的列有索引,MySQL 能夠快速到達一個位置去搜索數據文件,而不必查看所有數據,那麼將會節省很大一部分時間。

索引分類

先來了解一下索引都有哪些分類。

從邏輯上來對 MySQL 進行分類,主要分爲下面這幾種

索引使用

索引可以在創建表的時候進行創建,也可以單獨創建,下面我們採用單獨創建的方式,我們在 cxuan004 上創建前綴索引

我們使用 explain 進行分析,可以看到 cxuan004 使用索引的情況

如果不想使用索引,可以刪除索引,索引的刪除語法是

索引使用細則

我們在 cxuan005 上根據 id 和 hash 創建一個複合索引,如下所示

create index id_hash_index on cxuan005(id,hash);

然後根據 id 進行執行計劃的分析

explain select * from cxuan005 where id = '333';

可以發現,即使 where 條件中使用的不是複合索引(Id 、hash),索引仍然能夠使用,這就是索引的前綴特性。但是如果只按照 hash 進行查詢的話,索引就不會用到。

explain select * from cxuan005 where hash='8fd1f12575f6b39ee7c6d704eb54b353';

如果 where 條件使用了 like 查詢,並且 % 不在第一個字符,索引纔可能被使用。

對於複合索引來說,只能使用 id 進行 like 查詢,因爲 hash 列不管怎麼查詢都不會走索引。

explain select * from cxuan005 where id like '%1';

可以看到,如果第一個字符是 % ,則沒有使用索引。

explain select * from cxuan005 where id like '1%';

如果使用了 % 號,就會觸發索引。

如果列名是索引的話,那麼對列名進行 NULL 查詢,將會觸發索引。

explain select * from cxuan005 where id is null;

還有一些情況是存在索引但是 MySQL 並不會使用的情況。

關於設置索引但是索引沒有生效的場景還有很多,這個需要小夥伴們工作中不斷總結和完善,不過我上面總結的這些索引失效的情景,能夠覆蓋大多數索引失效的場景了。

查看索引的使用情況

在 MySQL 索引的使用過程中,有一個 Handler_read_key 值,這個值表示了某一行被索引值讀的次數。Handler_read_key 的值比較低的話,則表明增加索引得到的性能改善不是很理想,可能索引使用的頻率不高。

還有一個值是 Handler_read_rnd_next,這個值高則意味着查詢運行效率不高,應該建立索引來進行搶救。這個值的含義是在數據文件中讀下一行的請求數。如果正在進行大量的表掃描,Handler_read_rnd_next 的值比較高,就說明表索引不正確或寫入的查詢沒有利用索引。

MySQL 分析表、檢查表和優化表

對於大多數開發者來說,他們更傾向於解決簡單 SQL 的優化,而複雜 SQL 的優化交給了公司的 DBA 來做。

下面就從普通程序員的角度和你聊幾個簡單的優化方式。

MySQL 分析表

分析表用於分析和存儲表的關鍵字分佈,分析的結果可以使得系統得到準確的統計信息,使得 SQL 生成正確的執行計劃。如果用於感覺實際執行計劃與預期不符,可以執行分析表來解決問題,分析表語法如下

analyze table cxuan005;

分析結果涉及到的字段屬性如下

Table:表示表的名稱;

Op:表示執行的操作,analyze 表示進行分析操作,check 表示進行檢查查找,optimize 表示進行優化操作;

Msg_type:表示信息類型,其顯示的值通常是狀態、警告、錯誤和信息這四者之一;

Msg_text:顯示信息。

對錶的定期分析可以改善性能,應該成爲日常工作的一部分。因爲通過更新表的索引信息對錶進行分析,可改善數據庫性能。

MySQL 檢查表

數據庫經常可能遇到錯誤,比如數據寫入磁盤時發生錯誤,或是索引沒有同步更新,或是數據庫未關閉 MySQL 就停止了。遇到這些情況,數據就可能發生錯誤: Incorrect key file for table: ' '. Try to repair it. 此時,我們可以使用 Check Table 語句來檢查表及其對應的索引。

check table cxuan005;

檢查表的主要目的就是檢查一個或者多個表是否有錯誤。Check Table 對 MyISAM 和 InnoDB 表有作用。Check Table 也可以檢查視圖的錯誤。

MySQL 優化表

MySQL 優化表適用於刪除了大量的表數據,或者對包含 VARCHAR、BLOB 或則 TEXT 命令進行大量修改的情況。MySQL 優化表可以將大量的空間碎片進行合併,消除由於刪除或者更新造成的空間浪費情況。它的命令如下

optimize table cxuan005;

我的存儲引擎是 InnoDB 引擎,但是從圖可以知道,InnoDB 不支持使用 optimize 優化,建議使用 recreate + analyze 進行優化。optimize 命令只對 MyISAM 、BDB 表起作用。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/CF0WODa-kCypJiQaA9XkDQ