MYSQL索引失效的本質探究以及優化思想(上)

==> 學習彙總(持續更新)
==> 從零搭建後端基礎設施系列(一)-- 背景介紹


摘要:爲什麼要寫這篇文章?因爲從網上搜索"索引失效的原因"時,要麼是一些片面的總結性用語,例如"如果條件中有or,即使其中有條件帶索引也不會使用",要麼就是對着一些例子搭配explain進行籠統的解釋。導致我經常看過就忘,究其根本原因就是沒理解透徹,所以我經過從官方文檔、博客和書籍等,來探究其內部索引使用的原理。鑑於內容較多,分爲上下兩篇進行分析,上篇主要了解索引原理以及查詢優化器的概念,下篇根據上篇學到的知識並結合查詢優化器,對於各種索引失效場景進行分析以及SQL調優思想總結。另外,會有一篇專門分析查詢優化器的文章。


一、索引是個什麼東西?

  • 其實我覺得字典、圖書館的類比已經挺形象的了。就拿字典來說,如果你想查"hello"這個單詞,是不是第一反應是先去目錄那找到"H"開頭的單詞,接着在"H"下面繼續跳到第二個字母是"E"的單詞,依次類推,跳幾次就能很快定位到這個單詞了。但是跟這個單詞相關聯的僅僅是一個頁碼N,所以我們接着跳到第N頁,又發現這一頁有很多單詞,這時候我們只能依次遍歷這一頁,才能找到"hello"這個單詞的詳細釋義。如下圖所示
    在這裏插入圖片描述
    如果沒有索引,我們如何找這個單詞?很容易想象,在一本厚厚的字典裏,一頁一頁的遍歷查找,雖然有序的話,還是可以跳頁,但是需要過濾的信息量太大。
  • 回到數據庫中,其實思想也是一樣的,相較於全表掃描,那通過索引定位是不是要快很多?所以數據庫中才會造出那些個索引出來。

二、MYSQL中的B+樹索引類型分類和原理分析
mysql中用的最多的就是B+樹索引,那這些索引如何分類呢?大家肯定已經知道非常多的索引類型名詞,眼花繚亂,羣魔亂舞。其實吧,mysql中的索引其實就分爲2大類分別是聚集索引輔助索引,其它都是按照功能分類造的名詞,不需要強行去背它,只要理解了這兩類索引的區別即可。最後還有稍微特殊一點的聯合索引會單獨說一下。

  • MYSQL中的B+樹是什麼樣的
    先看一個非常簡單的圖
    在這裏插入圖片描述
    從圖中可以得出以下幾個結論
    a.只有葉子節點稱爲數據節點,並且它存儲了完整的數據
    b.目錄節點只存放能夠找到下層目錄節點和數據節點的信息
    c.不管是目錄節點還是數據節點,同一層次的節點用雙鏈表相互連接
    d.不管是目錄節點還是數據節點,內部都用單鏈表連接

    以上4個結論還比較表面,繼續看一張比較詳細的圖
    在這裏插入圖片描述
    從圖中可以得出以下幾個結論(假設圖中數據節點的記錄分別是id和name兩個字段)
    a.所有的節點都是一個數據頁
    b.目錄節點存放的記錄信息只有key對應的數據頁
    c.遍歷數據節點能夠得到按索引字段有序的記錄
    d.數據頁內並不是直接依次遍歷得到記錄,而是通過頁目錄進行二分查找

    mysql中的B+樹就長這樣了,這也爲什麼說索引即數據,指的就是索引(聚集索引和輔助索引結構都長這樣,只是節點中的記錄不一樣。)中的每一個節點都是數據頁。還有一點需要注意,mysql搜索的時候是按頁搜索,定位到頁之後纔會將頁中的數據加載到內存進行查找。因爲頁中的記錄是通過二分查找+記錄組內遍歷,速度非常快,耗時忽略不計。

  • 聚集索引
    那什麼是聚集索引?聚集索引的數據節點存放的是完整的記錄。假設一個表有idnameage字段,爲了方便畫圖,name假設只有單個字母a~z。如下圖所示
    在這裏插入圖片描述

    從圖中又可以得到幾個結論
    a.聚集索引的數據節點按照主鍵id從左到右依次遞增。
    b.聚集索引的數據節點存放了完整的記錄。
    c.聚集索引的數據節點除了主鍵id是有序的,其它字段都是無序的。

  • 輔助索引
    那什麼是輔助索引?可以想象一下,如果name這一列沒有建立索引,根據name查找的時候,是不是得去遍歷聚集索引下面的所有數據節點中的記錄一一比較呢?那能有什麼更快速的方法嗎?答案就是爲name建立一個索引,通過name定位到主鍵id,然後回到聚集索引中進行查找,這樣速度就非常快。那可能有人會想問,爲什麼不直接爲name建立一個聚集索引,這樣就能直接在數據節點找到完整的記錄信息了。是可以這麼做,但是會增加空間消耗,重複存儲冗餘數據了。所以起名爲輔助索引顧名思義,這個索引只起到一個輔助作用,真正查找數據還得回到聚集索引中找。如下圖所示,爲name建立一個輔助索引。
    在這裏插入圖片描述
    從圖中又可以得到幾個結論
    a.數據節點中,從左到右,按照name從小到大排序。
    b.數據節點中,只有name和主鍵id兩列數據。
    c.主鍵id在不同name中是亂序的。

    例如查找name=’a‘的時候,會找到三條數據,對應的主鍵id是1、22、30。然後回到聚集索引中,根據主鍵一個個查找,一共要進行三次回表操作。
    在這裏插入圖片描述

  • 聯合索引
    聯合索引也是輔助索引的一種,接下來以nameage建立一個聯合索引。
    在這裏插入圖片描述
    從圖中又可以得到幾個結論
    a.聯合索引中,數據節點從左到右依次按照第一個字段從小到大排序。
    b.聯合索引中,數據節點中,第一個字段值相同,第二個字段按照從小到大排序。
    c.聯合索引中,能夠單獨使用第一個字段作爲索引查詢,但是不能單獨使用第二個字段作爲索引查詢。

  • Q&A

    • 什麼是頁目錄?
      先看一下<MYSQL技內幕:InnoDB存儲引擎>這本書中的介紹

      在這裏插入圖片描述

      用大白話解釋就是,一個數據頁內會有很多記錄,並且都是用單鏈表來連接,假設有1000條記錄,如果沒有頁目錄,最壞情況下,需要遍歷1000次到最後一條記錄。所以就想到了一種用少量空間換時間的辦法,將1000條記錄分成100組,每組記錄數10條,然後用一個數組,將每一組的第一個地址偏移量存到數組中,當進行查找的時候,使用二分查找,定位到最後一組記錄,再進行遍歷,這樣只需要遍歷27次就能找到數據,時間上是不是大大減少了呢?用圖來表示就像這樣
      在這裏插入圖片描述
      例如現在要查找id=11,步驟是通過頁目錄二分查找,定位到0x20(9 < 11 < 13),然後從id=9依次遍歷三次得到id=11這個結果。
      再舉個不是數字的例子
      在這裏插入圖片描述
      可以看到,頁目錄中存的是地址偏移,二分查找的時候,通過地址偏移拿到實際數據進行比較。

    • B+樹的查找過程?
      當初作爲小白的我,天真的以爲是將整顆B+樹加載到內存中進行查找,現在才明白,其實是先在磁盤中查找到相應的頁,然後纔將這些頁加載到內存中進行查找。可以細品mysql書籍裏面經常說到多少多少次磁盤I/O查找,這不就是明着說B+樹的查找過程是先在磁盤查找的嗎?

三、什麼是查詢優化器?
那什麼是查詢優化器?那我們得先了解MYSQL的查詢流程,從客戶端提交到服務端執行都經歷什麼?
在這裏插入圖片描述
可以看到,提交引擎查詢之前,會有一個查詢優化的過程,在這一步,mysql真的是做了很多工作,可謂是絞盡腦汁幫用戶"愚蠢的行爲"買單。我們都知道explain這個關鍵字,可以幫助我們知道某條SQL語句的執行計劃。而這個執行計劃就是查詢優化器經過優化後,最終選擇的它認爲的最優的執行計劃。因爲查詢優化器內容實在太多,如果不細講,會影響下篇分析索引失效的本質,所以在本篇最後,先將執行執行計劃的各個參數含義列一遍,然後會專門寫一篇查詢優化器的原理分析。
在這裏插入圖片描述
官方文檔裏面的簡單解釋
在這裏插入圖片描述

四、總結

  • 索引就像是一本字典的目錄,能快速幫你定位到需要查找的數據,付出的代價就是字典的前面會多出幾頁甚至幾十頁的目錄出來。
  • 爲什麼需要索引?爲了快速定位數據唄。
  • MYSQL B+樹中的索引有哪些?聚集索引輔助索引
  • B+樹索引由目錄節點數據節點構成,這兩種節點都稱爲數據頁,因爲它們使用的結構是一樣的,只是存放的數據不同。
  • 數據頁是由頁目錄記錄構成的,數據頁中會有成百上千條記錄,爲了快速定位查找,犧牲了一些空間,造出了頁目錄,其實就是一個數組,然後將記錄分成N組,將每組的偏移量存入數組,就能通過二分查找+記錄組內遍歷進行快速定位了。
  • MYSQL查找的時候,會先從磁盤定位到需要用到的頁,然後才加載到內存進行查找。
  • 查詢優化器其實就是一個愛管閒事的玩意,不管你怎麼造,它都會盡可能的幫你糾正,少走彎路。所以當你使用explain的時候,會發現很多奇奇怪怪的現象,和自己想的完全不一樣。這時候就只有深入去探究它到底是如何進行優化的,才能掌握explain真正的威力。
  • 這裏推薦一下官方文檔、掘金小冊中的從根兒上理解 MySQLMYSQL技內幕:InnoDB存儲引擎。我之前是先看的InnoDB存儲引擎,但是比較難看懂,因爲很多官話,然後遇到從根兒上理解 MySQL,作者用通俗易懂的語言,將書上和官方文檔上的一些內容講解出來,確實是不錯。但是最全的還得是官方文檔,這個是最難看懂的,但卻是最權威的,所以我會將一些疑惑點,或者書上,其它作者沒有講清楚的點,自己去官方文檔上找出來研究。這樣下來,吸收日月精華,還有誰能阻擋?哈哈。再說一些額外的話,對於那些書籍、博客等講解的知識,自己但凡有一點疑惑,都要自己去權威的官方文檔中驗證,當然了,如果你能看懂源碼,這纔是最權威的,但是太難了,只能退而求其次去官方文檔中找答案了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章