Mysql的優化,一般是對索引優化,這里主要以innodb為主
索引是幫助MySQL高效獲取數據的排好序的數據結構,排好序是索引數據結構的特點,也是索引優化的前提。
1. 索引數據結構
索引底層使用B+樹作為其底層存儲結構。相較於二叉樹、紅黑樹、hash表、B樹而言,B+樹有自己獨特的優勢。
B+樹特點
- 非葉子節點不存儲data,只存儲索引(冗余),可以放更多的索引
- 葉子節點包含所有索引字段
- 葉子節點用指針連接,提高區間訪問的性能
1.1 聚集索引(主鍵索引)
聚集索引指索引包含了完整的數據記錄,一般主鍵索引是聚集索引
mysql使用B+樹存儲索引,頁大小默認為16K,mysql在查詢時會一次性將一個頁加載到內存中(一次磁盤I/O),在內存中可以快速定位下一次需要加載的頁(有一次磁盤I/O),所以一般精准查詢只需要進行三次磁盤I/O即可找到對應的數據。
1.2聯合索引
也稱非聚集索引,非聚集索引的data存儲的是聚集索引的值,如果返回的數據包含了非索引值,那么就需要通過聚集索引找到完整的記錄,這里就會產生回表,一般建議使用覆蓋索引,也就是查詢返回值都在索引列中,例如下圖,只返回name,age,position值的話,就不需要再去聚集索引查找其他數據,速度會快很多。
2. 優化建議
- 建表時盡量建主鍵(不建主鍵,mysql內部也會自己創建一個主鍵)
- 主鍵盡量使用整型的自增主鍵(自增主鍵會減少插入)
- 索引最佳實踐
- 全值匹配
- 最左前綴法則
- 不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
- 存儲引擎不能使用索引中范圍條件右邊的列
- 盡量使用覆蓋索引(只訪問索引的查詢(索引列包含查詢列)),減少 select * 語句
- mysql在使用不等於(!=或者<>),not in,not exists的時候無法使用索引會導致全表掃描<小於、>大於、<=、>=這些,mysql內部優化器會根據檢索比例、表大小等多個因素整體評估是否使用索引
- is null,is not null 一般情況下也無法使用索引
- like以通配符開頭(%abc)mysql索引失效會變成全表掃描操作
- 字符串不加單引號索引失效
- 少用or或in,用它查詢時,mysql不一定使用索引,mysql內部優化器會根據檢索比例、表大小等多個因素整體評估是否使用索引
3. Explain
- 模擬優化器執行SQL語句,分析你的查詢語句或是結構的性能瓶頸
- 如果 from 中包含子查詢,仍會執行該子查詢,將結果放入臨時表中
3.1 . id列
id列的編號是 select 的序列號,有幾個 select 就有幾個id,並且id的順序是按 select 出現的順序增長的。
id列越大執行優先級越高,id相同則從上往下執行,id為NULL最后執行
3.2 select_type列
select_type 表示對應行是簡單還是復雜的查詢
- simple:簡單查詢。查詢不包含子查詢和union
- primary:復雜查詢中最外層的 select
- subquery:包含在 select 中的子查詢(不在 from 子句中)
- derived:包含在 from 子句中的子查詢。MySQL會將結果存放在一個臨時表中,也稱為派生表
- union:在 union 中的第二個和隨后的 select
3.3 table列
這一列表示 explain 的一行正在訪問哪個表。
當 from 子句中有子查詢時,table列是
當有 union 時,UNION RESULT 的 table 列的值為<union1,2>,1和2表示參與 union 的 select 行id
3.4 type列
關聯類型或訪問類型,即MySQL決定如何查找表中的行
依次從最優到最差分別為:system > const > eq_ref > ref > range > index > ALL 一般來說,得保證查詢達到range級別,最好達到ref
NULL:mysql能夠在優化階段分解查詢語句,在執行階段用不着再訪問表或索引。例如:在索引列中選取最小值,可 以單獨查找索引來完成,不需要在執行時訪問表
3.5 possible_keys列
查詢可能使用哪些索引來查找
出現 possible_keys 有列,而 key 顯示 NULL 的情況,這種情況是因為表中數據不多,mysql認為索引 對此查詢幫助不大,選擇了全表查詢
3.6 key列
這一列顯示mysql實際采用哪個索引來優化對該表的訪問。如果沒有使用索引,則該列是 NULL。如果想強制mysql使用或忽視possible_keys列中的索引,在查詢中使用 force index、ignore index。
3.7 key_len列
顯示mysql在索引里使用的字節數,通過這個值可以算出具體使用了索引中的哪些列
key_len計算規則如下:
- 字符串,char(n)和varchar(n),n為字符數
- char(n):一個數字或字母占1個字節,一個漢字占3個字節,存漢子就是3n字節
- 如果存漢字則長度是 3n + 2 字節,加的2字節用來存儲字符串長度,因為 varchar是變長字符串
- 數值類型:
- tinyint:1字節
- smallint:2字節
- int:4字節
- bigint:8字節
- 時間類型
- date:3字節
- timestamp:4字節
- datetime:8字節
- 如果字段允許為 NULL,需要1字節記錄是否為 NULL
- 索引最大長度是768字節,當字符串過長時,mysql會做一個類似左前綴索引的處理,將前半部分的字符提取出來做索 引。
3.8 ref列
這一列顯示了在key列記錄的索引中,表查找值所用到的列或常量,常見的有:const(常量),字段名
3. 9rows列
是mysql估計要讀取並檢測的行數,注意這個不是結果集里的行數
3.10 Extra列
這一列展示的是額外信息