這是 MySQL 基礎系列的第四篇文章,之前的三篇文章見如下鏈接
一般傳統互聯網公司很少接觸到 SQL 優化問題,其原因是數據量小,大部分廠商的數據庫性能能夠滿足日常的業務需求,所以不需要進行 SQL 優化,但是隨著應用程序的不斷變大,數據量的激增,數據庫自身的性能跟不上了,此時就需要從 SQL 自身角度來進行優化,這也是我們這篇文章所討論的。
SQL 優化步驟
當面對一個需要優化的 SQL 時,我們有哪幾種排查思路呢?
通過 show 命令了解 SQL 執行次數
首先,我們可以使用show 命令查看服務器狀態信息。show 命令會顯示每個服務器變量 和 value,狀態變量是只讀的。如果使用 SQL 命令,可以使用 like 或者 where 條件來限制結果。like 可以對變量名做標準模式匹配。
圖我沒有截全,下面還有很多變量,讀者可以自己嘗試一下。也可以在操作系統上使用 -命令來獲取這些消息。
但是我執行 - 后,出現這個錯誤。
應該是我沒有輸入密碼的原因,使用 -P3306 -uroot -p -h127.0.0.1 -r -i 1 -后,問題解決。
這里需要注意一下 show 命令中可以添加統計結果的級別,這個級別有兩個
如果不指定統計結果級別的話,默認使用 級別。
對于 show 查詢出來的統計結果,有兩類參數需要注意下,一類是以Com_為開頭的參數,一類是以為開頭的參數。
下面是 Com_ 為開頭的參數,參數很多,我同樣沒有截全。
表示的是每個 xxx 語句執行的次數,我們通常關心的是 、 、、 語句的執行次數,即
以 為開頭的參數主要有
通過上面這些參數執行結果的統計,我們能夠大致了解到當前數據庫是以更新(包括插入、刪除)為主還是查詢為主。
除此之外,還有一些其他參數用于了解數據庫的基本情況。
下面這個博客匯總了幾乎所有 show 的參數,可以當作參考手冊。
定位執行效率較低的 SQL
定位執行效率比較慢的 SQL 語句,一般有兩種方式
MySQL 中提供了一個慢查詢的日志記錄功能,可以把查詢 SQL 語句時間大于多少秒的語句寫入慢查詢日志,日常維護中可以通過慢查詢日志的記錄信息快速準確地判斷問題所在。用 --log-slow- 選項啟動時, 會寫一個包含所有執行時間超過 秒的 SQL 語句的日志文件,通過查看這個日志文件定位效率較低的 SQL 。
比如我們可以在 f 中添加如下代碼,然后退出重啟 MySQL。
log-slow-queries?=?/tmp/mysql-slow.log
long_query_time?=?2
通常我們設置最長的查詢時間是 2 秒,表示查詢時間超過 2 秒就記錄了,通常情況下 2 秒就夠了,然而對于很多 WEB 應用來說,2 秒時間還是比較長的。
也可以通過命令來開啟:
我們先查詢 MySQL 慢查詢日志是否開啟
show?variables?like?"%slow%";
啟用慢查詢日志
set?global?slow_query_log='ON';
然后再次查詢慢查詢是否開啟
如圖所示,我們已經開啟了慢查詢日志。
慢查詢日志會在查詢結束以后才記錄,所以在應用反應執行效率出現問題的時候慢查詢日志并不能定位問題,此時應該使用show 命令查看當前 MySQL 正在進行的線程。包括線程的狀態、是否鎖表等,可以實時的查看 SQL 執行情況。同樣,使用 語句也能得到此信息。
下面就來解釋一下各個字段對應的概念
State 列非常重要,關于這個列的內容比較多,讀者可以參考一下這篇文章
這里面涉及線程的狀態、是否鎖表等選項,可以實時的查看 SQL 的執行情況,同時對一些鎖表進行優化。
通過 命令分析 SQL 的執行計劃
通過以上步驟查詢到效率低的 SQL 語句后,可以通過 或者 DESC 命令獲取 MySQL 如何執行 語句的信息,包括在 語句執行過程中表如何連接和連接的順序。
比如我們使用下面這條 SQL 語句來分析一下執行計劃
explain?select?*?from?test1;
上表中涉及內容如下
,查詢中最外層的 (如兩表做 UNION 或者存在子查詢的外層的表操作為 ,內層的操作為 UNION),比如下面這段子查詢。
UNION,在 UNION 操作中,查詢中處于內層的 (內層的 語句與外層的 語句沒有依賴關系時)。
:子查詢中首個(如果有多個子查詢存在),如我們上面的查詢語句,子查詢第一個是 sr()表,所以它的 是 。
上面就是 type 內容的大致解釋,關于 type 我們經常會在 SQL 調優的環節使用 分析其類型,然后改進查詢方式,越靠近 其查詢效率越高,越靠近 all 其查詢效率越低。
通過上面的分析,我們可以大致確定 SQL 效率低的原因,一種非常有效的提升 SQL 查詢效率的方式就是使用索引,接下來我會講解一下如何使用索引提高查詢效率。
索引
索引是數據庫優化中最常用也是最重要的手段,通過使用不同的索引可以解決大多數 SQL 性能問題,也是面試經常會問到的優化方式,圍繞著索引,面試官能讓你造出火箭來,所以總結一點就是索引非常非常重!要!不只是使用,你還要懂其原!理!
索引介紹
索引的目的就是用于快速查找某一列的數據,對相關數據列使用索引能夠大大提高查詢操作的性能。不使用索引,MySQL 必須從第一條記錄開始讀完整個表,直到找出相關的行,表越大查詢數據所花費的時間就越多。如果表中查詢的列有索引,MySQL 能夠快速到達一個位置去搜索數據文件,而不必查看所有數據,那么將會節省很大一部分時間。
索引分類
先來了解一下索引都有哪些分類。
從邏輯上來對 MySQL 進行分類,主要分為下面這幾種
索引使用
索引可以在創建表的時候進行創建,也可以單獨創建,下面我們采用單獨創建的方式,我們在 上創建前綴索引
我們使用進行分析,可以看到 使用索引的情況
如果不想使用索引,可以刪除索引,索引的刪除語法是
索引使用細則
我們在 上根據 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 查詢mysql 設置為當前時間,并且%不在第一個字符,索引才可能被使用。
對于復合索引來說,只能使用 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 索引的使用過程中,有一個值,這個值表示了某一行被索引值讀的次數。 的值比較低的話,則表明增加索引得到的性能改善不是很理想,可能索引使用的頻率不高。
還有一個值是t,這個值高則意味著查詢運行效率不高,應該建立索引來進行搶救。這個值的含義是在數據文件中讀下一行的請求數。如果正在進行大量的表掃描,t 的值比較高,就說明表索引不正確或寫入的查詢沒有利用索引。
MySQL 分析表、檢查表和優化表
對于大多數開發者來說,他們更傾向于解決簡單 SQL的優化,而復雜 SQL 的優化交給了公司的 DBA 來做。
下面就從普通程序員的角度和你聊幾個簡單的優化方式。
MySQL 分析表
分析表用于分析和存儲表的關鍵字分布mysql 設置為當前時間,分析的結果可以使得系統得到準確的統計信息,使得 SQL 生成正確的執行計劃。如果用于感覺實際執行計劃與預期不符,可以執行分析表來解決問題,分析表語法如下
analyze?table?cxuan005;
分析結果涉及到的字段屬性如下
Table:表示表的名稱;
Op:表示執行的操作, 表示進行分析操作,check 表示進行檢查查找, 表示進行優化操作;
:表示信息類型,其顯示的值通常是狀態、警告、錯誤和信息這四者之一;
:顯示信息。
對表的定期分析可以改善性能,應該成為日常工作的一部分。因為通過更新表的索引信息對表進行分析,可改善數據庫性能。
MySQL 檢查表
數據庫經常可能遇到錯誤,比如數據寫入磁盤時發生錯誤,或是索引沒有同步更新,或是數據庫未關閉 MySQL 就停止了。遇到這些情況,數據就可能發生錯誤: key file for table: ' '. Try to it. 此時,我們可以使用 Check Table 語句來檢查表及其對應的索引。
check?table?cxuan005;
檢查表的主要目的就是檢查一個或者多個表是否有錯誤。Check Table 對 和 表有作用。Check Table 也可以檢查視圖的錯誤。
MySQL 優化表
MySQL 優化表適用于刪除了大量的表數據,或者對包含 、BLOB 或則 TEXT 命令進行大量修改的情況。MySQL 優化表可以將大量的空間碎片進行合并,消除由于刪除或者更新造成的空間浪費情況。它的命令如下
optimize?table?cxuan005;
我的存儲引擎是 引擎,但是從圖可以知道, 不支持使用 優化,建議使用 + 進行優化。 命令只對 、BDB 表起作用。
“無影”已啟動大規模商用,未來傳統電腦會被淘汰嗎?