《深入淺出MySQL》讀書筆記五:SQL優化
一、SQL優化的一般步驟
show status like 'pattern%'; 檢視資料庫的執行時狀態
show variables like 'pattern%'; 檢視資料庫啟動時的配置資訊
1、首先需要定位執行效率有問題的SQL:
a、執行效率有問題的SQL一般都耗時較長,業務是有感知的,從而可以幫助定位
b、在MySQL啟動時,設定 slow_query_log 開啟慢查詢日誌 long_query_time 設定慢查詢時間閾值,這樣可以通過慢查詢日誌定位效率有問題的SQL。
2、通過 explain 分析sql的執行計劃,對於慢查詢sql主要看 possible keys 和 key ,分析索引的使用情況。
key為null的情況,則 sql沒有走索引。
可能原因:1)、沒有索引,需要建立 2)、存在索引,但是mysql選擇不走索引
使用索引的可能情況:a、多列索引,查詢條件使用了 索引中最左邊的列
b、like 'pattern%' 的情況 %在後面
c、大文字進行搜尋,建立 全文索引, 而不是 like '%pattern%'
d、如果為列 name建立索引,則 where name is null 將使用索引
存在索引但是不適用索引的情況:
a、範圍查詢表中大部分資料時,MySQL判斷全表掃描比索引更加合適的情況下,不會使用索引
b、使用 or分隔開的條件,當所有的條件列都 建立了 索引時,才會使用索引
c、列型別是 字串型別,查詢時 不加 引號 就 不會使用索引(雖然會進行型別的轉換),列型別是 整數類 型,查詢時 加了 引號,也會走索引
二、優化的常見方法
1、表優化
對 MyISAM和InnoDB型別的表來說,可以定期 分析表,檢查表,優化表
analyze table b; 分析表 使得系統得到準確的統計資訊,是的SQL能夠生成正確的執行計劃
check table b; 檢查表 檢視是否存在錯誤
optimize table b; 優化表,當表中存在動態型別(varchar text blob)時,對這些欄位頻番的更新和刪除會造成大量的空間碎片,優化表可以對錶空間碎片進行整理,減少空間的浪費
2、SQL優化
a、優化 INSERT:同一客戶插入多條資料時,將所有的資料 組裝為一條SQL語句提交;不同客戶端插入多行,可以使用 insert delayed 語句,在對資料實時性要求不高的情況下可以使用,很快的原因在於資料並沒有真正插入檔案,而是儲存在記憶體的佇列中等待插入;可以配置資料庫,或者在建表時指定 資料目錄和索引目錄存放到不同的磁碟上,平均分佈磁碟IO,效能會有所提高;當從一個文字檔案裝載一個表時,使用 load data infile 通常比 使用很多的 insert語句快很多
b、優化GROUP BY:預設情況下,MySQL對所有 group by d1,d2 中的 欄位進行排序,類似於 加上 order by d1,d2
explain select d2, count(d2) from b group by d2;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: b
partitions: NULL
type: index
possible_keys: d1
key: d1
key_len: 9
ref: NULL
rows: 7
filtered: 100.00
Extra: Using index; Using temporary; Using filesort
1 row in set, 1 warning (0.00 sec)
其中 Extra中的 Using filesort 即 進行了排序操作
排序操作會帶來額外的開銷,如果 group by 的結果 對排序沒有要求,可以加上 order by null 顯示指定 不排序
c、優化 order by 語句:某些情況下,MySQL可以使用一個索引來滿足 order by子句,而不需要額外的排序。order by使用索引的條件:where條件和 order by 使用相同的索引,並且 order by順序和 索引順序相同,並且order by 的欄位都是 升序或者降序
舉個栗子:
使用索引:
SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;
SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC;
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
不適用索引:
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC; --order by 的欄位混合 ASC 和 DESC SELECT * FROM t1 WHERE key2=constant ORDER BY key1; --用於查詢行的關鍵字與 ORDER BY 中所使用的不相同
SELECT * FROM t1 ORDER BY key1, key2; --對不同的關鍵字使用 ORDER BY
d、優化巢狀查詢:有些情況下,可以使用 連線操作代替 巢狀查詢,連線(JOIN)更有效率的原因在於,MySQL不需要在記憶體中建立臨時表
e、優化OR條件:為 or 的所有條件列都 建立索引,where a = 2 or b = 2 當 a、b都有各自的獨立索引時,查詢可以使用索引,而當 a、b只有組合索引時,查詢不會走 索引。
f、使用SQL提示:use index、ignore index、force index 來強制 使用、忽略相關索引。
3、資料庫物件的優化
a、根據實際情況,或者在 使用一段時間之後,根據統計結果,選擇或修改欄位的型別 為 更加合適的型別和長度
b、MyISAM型別的表,可以進行拆分提高表的訪問效率
水平拆分:各個表的結構完全一樣,但是 儲存的資料 類別不同,按照某個欄位分類(地區,月份)。適用於 資料量很大,增長很快,並且資料可以進行分類的場合。優點在於:分割後,降低了查詢時需要讀的資料和索引的頁數,降低索引的層數,提高了查詢速度。缺點在於:增加了複雜度,查詢所有的資料需要 UNION操作;在索引關鍵字不大、資料增長速度不那麼快的情況下,水平拆分的查詢速度和 不拆分的情況下走索引的查詢速度相比,可能不會有顯著的提高,從而 水分拆分帶來的複雜度 成為了 很大的問題。
垂直拆分:將 主鍵和一些列放在一個表中,主鍵和另外一些列放在另一個表中。可以將常用列和不常用的列分開,拆分之後,資料行變小,一個數據頁可以存放更多的資料,在查詢時就會減少I/O次數。 缺點在於 冗餘列的管理,查詢所有的資料需要 JOIN操作。
c、逆規範化-冗餘列:在表中增加必要的冗餘列,從而降低查詢時 連線的需求。問題在於:冗餘列的更新,可以考慮 建立觸發器,來統一更新冗餘列。
d、統計查詢的情況下,可以使用中間表提高查詢的速度。例如,統計使用者的月賬單,可以先將 當月的資料使用 insert into ...select * from... 匯入到建立的中間表中,然後在 中間表中進行統計操作。 優點:速度更快,而且可以按需建立索引和增加欄位來輔助統計操作。