網路程式設計總結
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列
這一列展示的是額外資訊