天天看點

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

摘要

索引是資料庫裡重要的組成部分,也是提高查詢效率必備的知識點。本文将會介紹索引作用、索引類型、索引優化以及索引底層結構,也算是對索引知識的一次歸納。

一、索引介紹

什麼是索引?

資料庫是用來存儲與讀取資料的,如何在這龐大的資料中查詢我們想要的那一行呢?最簡單的辦法便是掃描整個資料表,一一對比。然而這樣效率太低了。

如果我們有類似字典的功能,在查詢某行資料前,先到字典裡定位到行位置,再根據行位置找到具體資料,是否能更快呢?是的,索引就是這麼設計的。

一般的,我們往表裡插入某一行資料時,總會有額外的資訊來定位到這一行。這個資訊可能是一個指針位址,也可能是一個主鍵辨別。

在拿到這一行的定位資訊後,就可以将列資料和定位資訊做關聯了。下次想查找這個字段列所對應的行資料時,就可以先到關聯資訊裡搜尋,拿到定位資訊後直接查找即可。這就是索引,存儲了列和定位資訊,這定位資訊也可以了解指向資料記錄的引用指針。

需要注意的是,索引是由

存儲引擎

這個子產品來實作的,不同的存儲引擎有不同的實作方式。像 innodb 的主鍵就包含了行資料,找到了主鍵,也就找到了資料。

索引的分類

在資料庫裡,索引有好多種。我們可以從下面幾方面來分類歸納。

從資料結構劃分

:B+ 樹、hash 索引、全文索引

從實體結構劃分

:聚集索引、非聚集索引

從邏輯使用者劃分

:主鍵、唯一索引、複合索引、普通單列索引

其中, B+ 樹、 hash 索引、全文索引将會在後面具體介紹其底層結構,我們來看看其他的索引:

聚集索引:該索引除了存儲索引資訊還存儲了行資料,像剛剛提到的主鍵就是。找到它也就意味找到資料了。并且它的排序直接對應了實體存儲順序。

非聚集索引:該索引除了存儲索引資訊還存儲了定位到資料記錄的資訊,需要根據這個資訊再做一次查詢,才能擷取到資料,并且它的排序是邏輯上,不是實體存儲順序。

主鍵:唯一地辨別表中一條記錄的索引,不能有 NULL 值。在 InnoDB 裡,主鍵就是聚集索引。

唯一索引:索引所對應的列值裡是不能有重複值的,允許有 NULL 值。像剛剛提到的主鍵是不允許有 NULL 值的。

複合索引:有多列組合在一起的索引,但隻能按最左原則查找,即第一列字段才能被索引查找,後面隻是作為附帶資訊存放着。主要是為了找到索引後,不需要再去行資料裡撈資料,直接從索引裡提取字段資訊即可。

普通單列索引:沒有什麼限制條件的索引列。

索引的缺點

引入索引,并不總意味着高效,它是需要付出代價維護的。每當有資料需要添加更新時,都得更新對應的索引,這是額外的性能開銷,甚至有可能有出現死鎖。

另外,索引是需要占用磁盤空間的,不能無限制的添加索引,要有針對性的建索引。

二、索引的使用

使用原則

索引之是以那麼快,是因為我們将平時查詢頻率較高的字段單獨維護了起來。當我們有多個查詢選項,多個查詢條件就不一定能發揮作用了,是以索引的使用是有注意事項的,下面總結了一些:

  • where 裡最經常用到的查詢字段才建索引,能利用主鍵 id,就用主鍵 id 來增删改查
  • 按最左比對原則,将多個單列索引改為複合索引,減少維護量
  • 盡量挑選擇度高,也就是重複率低的列作為索引,像性别這種列就不适合了,會在 B+ 樹裡做多層次多範圍的搜尋,還不如全表掃描呢
  • 查找時,不對索引列做函數計算,否則不能使用到索引
  • 查詢條件盡量用 union 來取代 or
  • like 用法: ‘列%’ 這樣還是可以用到索引的,'%列%' 就不行了
  • IS NULL,IS NOT NULL 是用不到索引的
  • 在 order by,group by 裡盡量使用索引字段
  • join 的 on 條件裡盡量使用索引字段

性能分析

當我們使用了索引後,又如何知道它有沒有使用到索引呢?我們可以借助執行計劃來分析,執行計劃是 mysql 根據我們的查詢語句進行一系列的分析後得到的優化方案。我們可以通過執行計劃來擷取執行過程。

執行計劃的擷取:

explain select 語句

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

涉及的字段含義如下:

  • id: 該 SELECT 辨別符
  • select_type: 該 SELECT 類型
  • table: 輸出行的表
  • partitions: 比對的分區
  • type: 聯接類型
  • possible_keys: 可供選擇的可能索引
  • key: 實際選擇的索引
  • key_len: 所選密鑰的長度
  • ref: 與索引比較的列
  • rows: 估計要檢查的行數
  • filtered: 按表條件過濾的行百分比
  • Extra: 附加資訊

其中,有個 type 字段,它的含義大概如下:

  • eq_ref: 使用到了 UNIQUE 或 PRIMARY KEY 索引
  • ref: 顯示索引的哪一列被使用了
  • ref_or_null: 對 Null 進行了索引優化
  • range: 索引範圍檢索
  • index: 索引掃描
  • unique_subquery: 使用了 in 子查詢,裡面涉及了主鍵字段
  • index_subquery: 使用了 in 子查詢,裡面涉及了非唯一索引
  • fulltext: 全文索引
  • all: 全表掃描資料

從上面大概就能分析出索引的使用情況了,如果是 all,那就是沒有用到索引了。

索引的的底層

前面提到過索引的種類時,細分了 B+ 樹、hash 索引、全文索引這三類。現在我們來具體看下對應的底層結構吧。

B+樹

在 B+ 樹之前還有二叉搜尋樹和 B 樹,我們來一步一步演化,看看有什麼不同,先來看二叉搜尋樹:

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

當要進行查找時,會按小于往左搜尋,大于往右搜尋的規則去尋找。二叉搜尋樹隻存了單個節點值,樹的高度有可能會很高,如果用來存儲索引資料,效率将會降低,不适用于 mysql 的索引,我們來看看 B 樹吧:

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

一個節點可以存儲多個資料值。當然,在插入删除時需要做對應的拆分或合并動作。

而且 B 樹允許在非葉子節點也存儲具體資料,這意味着在掃描搜尋時也會将資料加載進來,這無疑增加了磁盤 IO。

對于磁盤 IO 要求高的 mysql 而言,B 樹也很不劃算,是以 B+ 樹成了最好的選擇,它長這樣的:

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

B+ 樹隻在葉子節點存儲具體的資料(注:資料可以是真正的行資料也可以是定位到行資料的指針位址),而非葉子節點值隻存放索引資料,這樣可以降低磁盤 IO,還能充分利用磁盤的預讀功能,批量的加載索引資料。

hash 索引

mysql 系列:搞定索引摘要一、索引介紹二、索引的使用索引的的底層總結

hash 索引将列通過 hash 運算得到 hash code,然後将 hash code 跟資料行的指針位址關聯在一起,下次查找時隻需查找對應 hash code 的資料行位址即可。

hash 索引非常的緊湊,查找速度很快,适用于記憶體存儲引擎的應用。不過它隻能精确查詢,不支援範圍查找,也不能直接進行排序。限制還是挺多的。

全文索引

全文索引主要是用于文檔查找,像我們可能會從多篇文章中查找包含某些詞語的文章,這時就可以使用全文索引了。雖然 like 也可以使用,但是效率太低了。

全文索引在接收到文檔時,會對它進行分詞處理,以擷取到關鍵詞。然後會将關鍵詞和屬于這個文檔的 id 關聯起來。

下次查找,就會先到關鍵詞清單裡找到關聯的文檔 id ,最後利用文檔 id 去查找到文檔資料。

總結

索引所涉及的知識點還是挺多的,從了解索引到用好索引再到優化索引,我想這應該是我們進行查詢優化的必經之路吧。希望本文能為大家帶來不一樣的認識,也歡迎一起探讨!