實際開發中Sql效能優化套路
實際開發中Sql效能優化套路
sql優化套路
一般都是壓測時,測試報告顯示某介面響應時間過長。這時,我們就要進行優化了。優化的方式有很多種,加快取,加訊息佇列,優化業務邏輯、程式碼,調優系統引數,給機器加配置,調優sql等。這裡,我們主要探討的是sql優化。
定位慢sql
我們一般定位慢sql主要有以下3種方式:
- 匯出慢查詢日誌 ,分析日誌,找出耗時的sql;
- 進入命令列介面,執行show full processlist,檢視當前資料庫的執行狀態;
- 對照 壓測報告 ,找出耗時的介面,跟蹤到程式碼層面,在嘗試優化業務邏輯的同時,篩選出可能的慢sql;
造資料
- 儘量模擬生產環境
- mysql會進行查詢優化,根據當前狀況,選擇消耗代價較小的索引,不一定會走到對應索引上
解釋Sql
EXPLAIN
在MySQL中可以使用EXPLAIN檢視SQL執行計劃,用法:EXPLAIN SELECT * FROM tb_item
結果說明
- id
SELECT識別符。這是SELECT查詢序列號。這個不重要。 - select_type
表示SELECT語句的型別。
有以下幾種值
- SIMPLE
表示簡單查詢,其中不包含連線查詢和子查詢。 - PRIMARY
表示主查詢,或者是最外面的查詢語句。
- UNION
表示連線查詢的第2個或後面的查詢語句。
- DEPENDENT UNION
UNION中的第二個或後面的SELECT語句,取決於外面的查詢。 - UNION RESULT
連線查詢的結果。 - SUBQUERY
子查詢中的第1個SELECT語句。
- DEPENDENT SUBQUERY
子查詢中的第1個SELECT語句,取決於外面的查詢。 - DERIVED
SELECT(FROM 子句的子查詢)。
table
表示查詢的表。
type(重要)
表示表的連線型別。
以下的連線型別的順序是從最佳型別到最差型別:
- system
表僅有一行,這是const型別的特列,平時不會出現,這個也可以忽略不計。 - const
資料表最多隻有一個匹配行,因為只匹配一行資料,所以很快,常用於PRIMARY KEY或者UNIQUE索引的查詢,可理解為const是最優化的。
- eq_ref
mysql手冊是這樣說的:“對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接型別,除了const型別。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY”。eq_ref可以用於使用=比較帶索引的列。
- ref
查詢條件索引既不是UNIQUE也不是PRIMARY KEY的情況。ref可用於=或<或>操作符的帶索引的列。
- ref_or_null
該聯接型別如同ref,但是添加了MySQL可以專門搜尋包含NULL值的行。在解決子查詢中經常使用該聯接型別的優化。
上面這五種情況都是很理想的索引使用情況。
- index_merge
該聯接型別表示使用了索引合併優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。 - unique_subquery
該型別替換了下面形式的IN子查詢的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一個索引查詢函式,可以完全替換子查詢,效率更高。 - index_subquery
該聯接型別類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr) - range
只檢索給定範圍的行,使用一個索引來選擇行。
- index
該聯接型別與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引檔案通常比資料檔案小。 - ALL
對於每個來自於先前的表的行組合,進行完整的表掃描。(效能最差)
possible_keys
指出MySQL能使用哪個索引在該表中找到行。
如果該列為NULL,說明沒有使用索引,可以對該列建立索引來提供效能。
key
顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。
可以強制使用索引或者忽略索引:
key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
注意:key_len是確定了MySQL將實際使用的索引長度。
ref
顯示使用哪個列或常數與key一起從表中選擇行。
rows
顯示MySQL認為它執行查詢時必須檢查的行數。
Extra
該列包含MySQL解決查詢的詳細資訊
- Distinct:MySQL發現第1個匹配行後,停止為當前的行組合搜尋更多的行。
- Not exists:MySQL能夠對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,不再為前面的的行組合在該表內檢查更多的行。
- range checked for each record (index map: #):MySQL沒有發現好的可以使用的索引,但發現如果來自前面的表的列值已知,可能部分索引可以使用。
- Using filesort:MySQL需要額外的一次傳遞,以找出如何按排序順序檢索行。
- Using index:從只使用索引樹中的資訊而不需要進一步搜尋讀取實際的行來檢索表中的列資訊。
- Using temporary:為了解決查詢,MySQL需要建立一個臨時表來容納結果。
- Using where:WHERE 子句用於限制哪一個行匹配下一個表或傳送到客戶。
- Using sort_union(…), Using union(…), Using intersect(…):這些函式說明如何為index_merge聯接型別合併索引掃描。
- Using index for group-by:類似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,可以用來查 詢GROUP BY或DISTINCT查詢的所有列,而不要額外搜尋硬碟訪問實際的表。
使用索引查詢需要注意
索引可以提供查詢的速度,但並不是使用了帶有索引的欄位查詢都會生效,有些情況下是不生效
的,需要注意!
使用LIKE關鍵字的查詢
在使用LIKE關鍵字進行查詢的查詢語句中,如果匹配字串的第一個字元為“%”,索引不起作用。只有“%”不在第一個位置,索引才會生效。
使用聯合索引的查詢
MySQL可以為多個欄位建立索引,一個索引可以包括16個欄位。對於聯合索引,只有查詢條件中使用了這些欄位中第一個欄位時,索引才會生效。
使用OR關鍵字的查詢
查詢語句的查詢條件中只有OR關鍵字,且OR前後的兩個條件中的列都是索引時,索引才會生效,否則,索引不生效。
子查詢優化
MySQL從4.1版本開始支援子查詢,使用子查詢進行SELECT語句巢狀查詢,可以一次完成很多邏輯上需要多個步驟才能完成的SQL操作。
子查詢雖然很靈活,但是執行效率並不高。
執行子查詢時,MYSQL需要建立臨時表,查詢完畢後再刪除這些臨時表,所以,子查詢的速度會受到一定的影響。
優化:
可以使用連線查詢(JOIN)代替子查詢,連線查詢時不需要建立臨時表,其速度比子查詢快。
資料庫結構優化
一個好的資料庫設計方案對於資料庫的效能往往會起到事半功倍的效果。
需要考慮資料冗餘、查詢和更新的速度、欄位的資料型別是否合理等多方面的內容。
將欄位很多的表分解成多個表
對於欄位較多的表,如果有些欄位的使用頻率很低,可以將這些欄位分離出來形成新表。
因為當一個表的資料量很大時,會由於使用頻率低的欄位的存在而變慢。
增加中間表
對於需要經常聯合查詢的表,可以建立中間表以提高查詢效率。
通過建立中間表,將需要通過聯合查詢的資料插入到中間表中,然後將原來的聯合查詢改為對中間表的查詢。
增加冗餘欄位
設計資料表時應儘量遵循正規化理論的規約,儘可能的減少冗餘欄位,讓資料庫設計看起來精緻、優雅。但是,合理的加入冗餘欄位可以提高查詢速度。
表的規範化程度越高,表和表之間的關係越多,需要連線查詢的情況也就越多,效能也就越差。
注意:
冗餘欄位的值在一個表中修改了,就要想辦法在其他表中更新,否則就會導致資料不一致的問題。