myesn

myEsn2E9

hi
github

MySQL 索引優化

前綴索引優化#

在字符串字段的前幾位字符上建立索引

局限性:

  • order by 無法使用前綴索引
  • 無法把 [前綴索引] 用作 [覆蓋索引]

覆蓋索引優化#

含義:指 SQL 中 select 的所有字段,在二級索引 B+Tree 的葉子節點上都能找得到,即從二級索引的 B+Tree 中查詢得到記錄,而不需要通過聚簇索引查詢獲得,可以避免回表的操作

比如只需商品的名稱、價格時,建立聯合索引即 [商品 ID、名稱、價格] 作為一個聯合索引。如果索引中存在這些數據,查詢將不會再次檢索主鍵索引,從而避免回表(減少 I/O 操作)

主鍵索引最好自增#

InnoDB 創建主鍵索引默認為聚簇索引,數據被存放在了 B+Tree 的葉子節點上(葉子節點自動排序)

使用自增主鍵:每次插入一條新記錄,都是追加操作,不需要重新移動數據。

使用非自增主鍵:由於每次插入主鍵的索引值都是隨機的,因此每次插入新的數據時,就可能會插入到現有數據頁中間的某個位置,這將不得不移動其它數據來滿足新數據的插入,甚至需要從一個頁面複製數據到另外一個頁面,我們通常將這種情況稱為頁分裂頁分裂還有可能會造成大量的內存碎片,導致索引結構不緊湊,從而影響查詢效率

舉個例子,假設某個數據頁中的數據是 1、3、5、9,且數據頁滿了,現在準備插入一個數據 7,則需要把數據頁分割為兩個數據頁
image

出現頁分裂時,需要將一頁的記錄移動到另外一頁,性能會受到影響,同時頁空間的利用率下降,造成存儲空間的浪費

而如果記錄是順序插入的,例如插入數據 11,則只需開闢新的數據頁,也就不會發生頁分裂:
image

主鍵字段的長度不要太大,因為主鍵字段長度越小,意味著二級索引的葉子節點越小(二級索引的葉子節點存放的數據是主鍵值),這樣二級索引佔用的空間也就越小

索引列設置 NOT NULL#

為了更好的利用索引,索引列要設置為 NOT NULL 約束。有兩個原因:

  • 索引列存在 NULL 就會導致優化器在做索引選擇的時候更加複雜,更加難以優化,因為可為 NULL 的列會使索引、索引統計和值比較都更複雜,比如進行索引統計時,count 會省略值為 NULL 的行
  • NULL 值是一個沒意義的值,但是它會佔用物理空間,所以會帶來存儲空間的問題,因為 InnoDB 存儲記錄的時候,如果表中存在允許為 NULL 的字段,那麼 **行格式 (opens new window)至少會用 1 字節空間存儲 NULL 值列表 **,如下圖的紫色部分:
    image

防止索引失效#

用上了索引並不意味著查詢的時候會使用到索引。索引失效的常見情況:

  • 使用左或左右模糊匹配,即 like '%xx'like '%xx%'
  • where 中對索引列做了計算、函數、類型轉換操作
  • 不遵守聯合索引最左匹配原則
  • 在 where 子句中,where 索引列 or 非索引列

實際過程中,需要查看執行計劃 (explain) 來判斷是否使用了索引,如下圖就是全表掃描沒有使用索引的查詢語句:
image

對於執行計劃的結果

  • possible_keys 字段表示可能用到的索引
  • key 字段表示實際用的索引,如果這一項為 NULL,說明沒有使用索引
  • key_len 表示索引的長度
  • rows 表示掃描的數據行數
  • 重點!!type 表示數據掃描類型執行效率從低到高的順序為:
    • All(全表掃描)!!儘量避免
    • index(全索引掃描)!!儘量避免
    • range(索引範圍掃描):至少要到這一級別
    • ref(非唯一索引掃描):存在重複值
    • eq_ref(唯一索引掃描):eq_ref 通常用於多表聯查中
    • const(結果只有一條的主鍵或唯一索引掃描):const 是與常量進行比較,查詢效率會更快
  • Extra:
    • !!避免 Using filesort:查詢語句中包含 group by,且無法利用索引排序時
    • !!避免 Using temporary:使用了臨時表保存的中間結果,MySQL 在對查詢結果排序時使用臨時表,常見於排序 order by 和分組查詢 group by
    • !!不錯 Using index:所需數據在二級索引的 B+Tree 中即可全部獲得,不需要再逐一回表獲取數據,也就是使用了覆蓋索引避免回表操作

參考#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。