MySQL系列(四) MySQL的索引和算法


  • 11 表結構

    • 表是關於特定實體的數據集合,這也是關系型數據庫的核心。
    • 在InnoDB中,表都是根據主鍵順序組織存放的,這種存儲方式的表成為索引組織表。
    • 所有數據都被邏輯的存放在一個空間中,稱之為表空間 tablespace。 表空間又由段 segment, 區 extent, 頁page 組成。 頁在一些文檔中有時也稱之為塊 block。
    • 一個區一般為1M,一個頁總是16KB,即一個區一共有64個連續的頁。
    • InnoDB中數據是按行進行存放的。每個頁存放的行是有硬性規定規定的,最多運行存放16 KB/2-200行數據,即7992行記錄。另外也有面向列的數據庫,優點是分析類SQL語句的執行及數據壓縮是非常有效的。面向列是當前數據庫發展的一個方向。
    • 內部是按照一種鏈表的結構來串連各個行記錄的,當前位置的記錄加上偏移量就是下條記錄的起始地址。
    • 行數據溢出,當行中數據過大時,頁中只保留了前786字節的前綴數據,之后是偏移量,指向行溢出頁。
  • 12 索引

    • B+樹索引

      • 平衡二叉樹的左旋和右旋

         

         

      • 概述

        B+樹是為磁盤或其他直接存取輔助設備設計的一種平衡查找樹。

        在B+樹中,所有記錄節點都是按鍵值的大小順序存放在同一層的葉子節點上,由各葉子節點指針進行連接。

        B+樹索引在數據庫中有一個特點是高扇出性,因此在數據庫中,B+樹的高度一般都在2~4層,這也就是說查找某一鍵值的行記錄時最多只需要2到4次IO。

        數據庫中的B+樹索引可以分為聚集索引(clustered inex)和輔助索引(secondary index),但是不管是聚集還是輔助的索引,其內部都是B+樹的,即高度平衡的,葉子節點存放着所有的數據。聚集索引與輔助索引不同的是,葉子節點存放的是否是一整行的信息。

      • 聚集索引

        • 聚集索引構造圖

           

        InnoDB 存儲引擎表是索引組織表,即表中數據按照主鍵順序存放。而聚集索引就是每張表根據主鍵構造一棵B+樹,葉子節點中存放的即為整張表的行記錄數據,也將聚集索引的葉子節點稱為數據頁。

        聚集索引的這個特性決定了索引組織表中數據也是索引的一部分。每個數據頁都通過一個雙向鏈表來進行鏈接。 數據頁的排序只能按照一顆B+樹進行,這也是每張表只能擁有一個聚集索引的根本原因。

        在多數情況下,查詢優化器傾向於采用聚集索引。因為聚集索引能夠在B+樹索引的葉子節點上直接找到數據。

        此外,由於定義了數據的邏輯順序,聚集索引能夠特別快地訪問針對范圍值的查詢。注:比如查詢倒數10個主鍵元素,數據頁是雙向鏈表進行鏈接的;比如范圍查詢,查詢500-1000的主鍵元素,主鍵都是順序存放的,可以直接按照區間查詢。

        數據頁上存放的是完整的每行的記錄,而在非數據頁的索引頁中,存放的僅僅是鍵值及指向數據頁的偏移量,而不是一個完整的行記錄。

        注:

        • 每張表中有一個聚集索引頁和一個或多個輔助索引頁,聚集索引頁存放的即是每個主鍵和數據頁的映射關系。主鍵是按照順序存放,查詢時使用二分查找。
        • 數據頁的子級單位並不直接是行,而是槽,槽的子級單位才是行。每個數據頁中保存一定數量的槽,每個槽中保存4-8個行記錄。
        • 通過聚集索引的頭節點數據,可以查詢到對應的數據頁、槽、槽中行記錄的偏移量。數據頁中保存着行記錄的起始和結束位置。每個行記錄的頭節點又保存着下一個行記錄的相對偏移量。
        • 因此通過主鍵就可以完成一張表的掃描。
        • 聚集索引和非聚集索引實際上是不同的B+樹,且聚集索引有且只有一顆B+樹,非聚集索引則根據索引的類型分別建立一顆。
      • 輔助索引(非聚集索引)

        • 輔助索引構造圖

           

        對於輔助索引,葉子節點並不包含行記錄的全部數據。

        葉子節點除了包含鍵值以外,每個葉子節點中的索引行中還包含了一個書簽

        該書簽用來告訴 InnoDB 存儲引擎哪里可以找到與索引相對應的行數據。書簽存放的即是相應行的聚集索引。

        輔助索引的存在並不影響數據在聚集索引中的組織,因此每張表上可以有多個輔助索引。

        當通過輔助索引來尋找數據時,InnoDB 存儲引擎會遍歷輔助索引並通過葉級別的指針獲得對應的聚集索引,然后再通過聚集索引來找到一個完整的行記錄。

        舉例來說,如果在一棵高度為3的輔助索引樹中查找數據,那需要對這棵輔助索引樹遍歷3次找到指定聚集索引,如果聚集索引樹的高度同樣為3,那么還需要對聚集索引樹進行3次查找,最終找到一個完整的行數據所在的頁,因此一共需要6次邏輯IO訪問以得到最終的一個數據頁,槽中的查找因為在內存中不算一次IO。

        對於其他的一些數據庫,如Microsoft SQL Server數據庫,其有一種稱為堆表的表類型,即行數據的存儲按照插入的順序存放。堆表的特性決定了堆表上的索引都是非聚集的,主鍵與非主鍵的區別只是是否唯一且非空。因此這時書簽是一個行標識符,可以用如“文件號:頁號:槽號”的格式來定位實際的行數據。

        • 覆蓋索引

          從輔助索引上就可以得到所需數據,而不用再通過主鍵進行索引。

          因為輔助索引存放的索引列和對應的值,以及書簽。

        • 聯合索引

          • 聯合索引結構圖

             

          指對表上的多個列建立索引。

          聯合索引是根據第一個索引值進行排序的,因此頁適用於第一個索引的查詢。比如(a,b),適用於 where a=xx 而不適用於 where b=xx 。

          聯合索引的第二個好處是已經對第二個鍵值進行了排序處理。例如,在很多情況下應用程序都需要查詢某個用戶的購物情況,並按照時間進行排序,最后取出最近三次的購買記錄,這時使用聯合索引可以避免多一次的排序操作,因為索引本身在葉子節點已經排序了。

      • OLTP 和 OLAP 中 B+樹的使用概述

        在了解了B+樹索引的本質和實現后,下一個需要考慮的問題是怎樣正確地使用B+樹索引。

        在OLTP應用中,查詢操作只從數據庫中取得一小部分數據,甚至在很多時候只取1條記錄,如根據主鍵值來取得用戶信息,根據訂單號取得訂單的詳細信息,這都是典型OLTP應用的查詢情況。在這種情況下,B+樹索引建立后,對該索引的使用應該只是通過該索引取得表中少部分的數據。這時建立B+樹索引才是有意義的,否則即使建立了,優化器也可能選擇不使用索引。

        對於OLAP應用,情況可能就稍顯復雜了。不過概括來說,在OLAP應用中,都需要訪問表中大量的數據,根據這些數據來產生查詢的結果,這些查詢多是面向分析的查詢,目的是為決策者提供支持。如這個月每個用戶的消費情況,銷售額同比、環比增長的情況。因此在OLAP中索引的添加根據的應該是宏觀的信息,而不是微觀,因為最終要得到的結果是提供給決策者的。例如不需要在OLAP中對姓名字段進行索引,因為很少需要對單個用戶進行查詢。但是對於OLAP中的復雜查詢,要涉及多張表之間的聯接操作,因此索引的添加依然是有部分意義的。

    • 全文索引

      • 概述

        全文檢索(Full-Text Search)是將存儲於數據庫中的整本書或整篇文章中的任意內容信息查找出來的技術。它可以根據需要獲得全文中有關章、節、段、句、詞等信息,也可以進行各種統計和分析。

      • 倒排索引

        全文檢索通常使用倒排索引來實現。倒排索引同B+樹索引一樣,也是一種索引結構。它在輔助表中存儲了單詞與單詞自身在一個或多個文檔中所在位置之間的映射。這通常利用關聯數組實現。

        數據的表現形式之一為:

        • full invertedindex,其表現形式為{單詞,(單詞所在文檔的ID,在具體文檔中的位置)}

        全文檢索的表中,有兩個列: word 和 ilist。word上設有索引。

        輔助表:倒排索引中存放 word 字段的物理表

      • 全文檢索索引緩存

        全文檢索索引緩存采用紅黑樹結構,根據(word, ilist) 進行排序。

        實現非常復雜,主要目的是為了提供全文索引的緩存,提高全文檢索的性能。

    • 哈希索引

      InnoDB存儲引擎使用哈希算法來對字典進行查找,其沖突機制采用鏈表方式,哈希函數采用除法散列方式。

      對於緩沖池頁的哈希表來說,在緩沖池中的Page頁都有一個chain指針,它指向相同哈希函數值的頁。而對於除法散列,m的取值為略大於2倍的緩沖池頁數量的質數。例如:當前參數innodb_buffer_pool_size的大小為10M,則共有640個16KB的頁。對於緩沖池頁內存的哈希表來說,需要分配640×2=1280個槽,但是由於1280不是質數,需要取比1280略大的一個質數,應該是1399,所以在啟動時會分配1399個槽的哈希表,用來哈希查詢所在緩沖池中的頁。

      InnoDB存儲引擎的表空間都有一個表ID,用戶所要查詢的應該是某個表空間的某個連續16KB的頁,即偏移量offset。InnoDB存儲引擎將space_id左移20位,然后加上這個space_id和offset,即關鍵字K=space_id<<20+space_id+offset,然后通過除法散列到各個槽中去。

      • 自適應哈希索引 AHI

        InnoDB存儲引擎會監控對表上各索引頁的查詢。如果觀察到建立哈希索引可以帶來速度提升,則建立哈希索引,稱之為自適應哈希索引。

        AHI 是通過緩沖池的B+樹頁構造而來,因此建立的速度很快,而且不需要對整張表構建哈希索引。InnoDB存儲引擎會自動根據訪問的頻率和模式來自動地為某些熱點頁建立哈希索引

        自適應哈希索引僅是數據庫自身創建並使用的,DBA本身並不能對其進行干預。自適應哈希索引經哈希函數映射到一個哈希表中,因此對於字典類型的查找非常快速,如 where id=1;

        自適應哈希索引建立的條件

        • 對這個頁的連續訪問模式必須是一樣的。
        • 以該模式訪問了100次
        • 頁通過該模式訪問了N次,N=表中記錄 * 1/16

        自適應哈希索引的優勢

        • 讀取和寫入速度可以提高2倍
        • 輔助索引的連接操作性能提高5倍


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM