1. 程式人生 > >深入了解MySQL的索引

深入了解MySQL的索引

另一個 硬盤 兩種 art 方便 之一 之前 空間 軟件

(一)關於存儲引擎

   創建合適的索引是SQL性能調優中最重要的技術之一。在學習創建索引之前,要先了解MySql的架構細節,包括在硬盤上面如何組織的,索引和內存用法和操作方式,以及存儲引擎的差異如何影響到索引的選擇。

   MySQL有很多種衍生版本,這些衍生版本支持更多不同種類的存儲引擎。本文主要討論三種MySQL引擎。

MyISAM一種非事務性的存儲引擎,是MySQL 5.5之前版本默認的存儲引擎。

InnoDB 最流行的事務性存儲引擎,從5.5版開始成為MySQL默認的引擎。

Memory 基於內存的,非事務性的以及非持久性的存儲引擎。

註意:

    從5.5版本開始,MySQL表的默認存儲引擎從MyISAM換成InnoDB,將會使用戶安裝那些依賴默認設置或者專門為MyISAM編寫的軟件包時帶來很大的影響。

(二)MySQL索引類型

    MySQL支持在所有關系數據庫表中創建主鍵、唯一鍵、不唯一的非主碼索引等多種類型的索引。此外MySQL還支持純文本和空間索引類型。

   MySQL內置的存儲引擎對各種索引技術有不同的實現方式,包括:B-樹,B+樹,R-樹以及散列類型。

   索引數據結構理論:

1.B-樹

B-樹中有兩種節點類型:索引節點和葉子節點。葉子節點是用來存儲數據的,而索引節點則用來告訴用戶存儲在葉子節點中的數據順序,並幫助用戶找到相應的數據。

   B-樹的搜索,從根節點開始,對節點內的關鍵字有序進行二分查找,如果命中則結束,否則進入查詢關鍵字所屬範圍的兒子節點,重復。直到所對應的兒子指針為空,或已經是葉子節點。

   B-樹是一種多路搜索樹:

   (1). 定義任意非葉子節點最多有M個兒子,且M>2;

   (2). 根節點的兒子數為[2,M];

   (3). 除根節點以外的非葉子節點的兒子數為[M/2,M];

   (4). 每個節點存放至少M/2-1(取上整)和至多M-1個關鍵字;

   (5). 非葉子節點的關鍵字個數=指向兒子節點的指針的個數-1;  

   (6). 非葉子節點的關鍵字:k[i]

   (7). 非葉子節點的指針:p[1],p[2],·····,p[M];其中p[1]指向的關鍵字小於k[1]的子樹,p[M]指向的關鍵字大於K[m-1]的子樹;

   (8). 所有的葉子節點位於同一層; 

 2.B+樹

B+樹數據結構是B-樹實現的增強版本。盡管B+樹支持B-樹索引的所有特性,它們之間最顯著的不同點在於B+樹中底層數據是根據被提及的索引列進行排序的。B+樹還通過葉子節點之間的附加引用來優化掃描性能。

   B+搜索和B-搜索不同,區別是B+樹只有達到葉子節點才命中(B-樹可以在非葉子節點命中),其性能等價於關鍵字全集做一次二分搜索。

  B+樹的特性:

 (1)所有關鍵字都出現在葉子節點的鏈表中,葉子節點相當於存儲數據的數據層。

 (2)不可能在非葉子節點上命中。

 (3)非葉子節點相當於是葉子節點的索引,葉子節點相當於數據層。

3.散列

 散列表數據結構是一種很簡單的概念,它將一種算法應用到給定值中以在底層數據存儲系統中返回一個唯一的指針或位置。散列表的優點是始終以線性時間復雜度找到需要讀取的行的位置,而不像B-樹那樣需要橫跨多層節點來確定位置。

4.通信R-樹

R-樹數據結構支持基於數據類型對幾何數據進行管理。目前只有MyISAM使用R-樹實現支持空間索引,使用空間索引也有很多限制,比如只支持唯一的NOT NULL列等。

5.全文本

 全文本結構也是一種MySQL采用的基本數據結構。這種數據結構目前只有當前版本MySQL中的MyISAM存儲引擎支持。5.6版本將要在InnoDB存儲引擎中加入全文本功能。全文本索引在大型系統中並沒有什麽實用的價值,因為大規模系統有很多專門的文件檢索產品。所以不用在介紹。

MySQL實現

   對B-樹,B+樹和散列等數據結構的基本概念有了一些了解之後,我們就可以開始討論MySQL通過支持它們的存儲引擎如何實現不同的算法。同時每種實現也對磁盤和內存使用情況有不同的影響,這一點在大型數據庫系統中是非常重要的考慮因素。

1.MyISAM的B-樹

 MyISAM存儲引擎使用B-樹數據結構來實現主碼索引、唯一索引以及非主碼索引。在MyISAM實現數據目錄和數據庫模式子目錄中,用戶可以找到和每個MySQL表對應的.MYD和.MYI文件。數據庫表上定義的索引信息就存儲在MYI文件中,該文件的塊大小是1024字節。這個大小是可以通過myisam-block-size系統變量分配。

$  ls -1h /var/lib/mysql/book/source_words.MY*

-rw-rw---- 1 mysql mysql  9.2M 2015-05-07 19:08

source_words.MYD

-rw-rw---- 1 mysql mysql 7.8M 2015-05-07 19:08

source_words.MYI

 這些文件結構的內部格式可以從MySQL免費源代碼中找到,也可以查看MySQL內部手冊。

在MyISAM中,非主碼索引的B-樹結構存儲索引值和一個指向主碼數據的指針,這是MyISAM和InnoDB的一個顯著區別。這一點導致了兩個存儲引擎的索引的不同工作方式。

 MyISAM索引是在內存的一個公共緩存中管理的,這個緩存的大小可以通過key_buffer_size或者其他命名鍵緩存來定義。這是根據統計和規劃的表索引的大小來設定緩存大小時主要的考慮因素。
  1. InnoDB的B+樹聚簇主碼

    InnoDB存儲引擎在它的主碼索引(也被稱為聚簇主碼)中使用了B+樹,這種結構把所有數據都和對應的主碼組織在一起,並且在葉子節點這一層上添加額外的向前和向後的指針,這樣就可以更方便地進行範圍掃描。

    在文件系統層面,所有InnoDB數據和索引信息都默認在公共InnoDB表空間中管理,否則管理員就通過innodb_data_file_path這個變量指定文件路徑。這是一個叫ibdatal文件。

    由於InnoDB用聚簇主碼存儲數據,底層信息占用的磁盤空間的大小很大程度上取決於頁面的填充因子。對於按序排列的主碼,InnoDB會用16K頁面的15/16作為填充因子。對於不是按序排列的主碼,默認情況下InnoDB會插入初始數據的時候為每一個頁面分配50%作為填充因子。

    在改索引的實現方式中B+樹的葉子節點上是data就是數據本身,key為主鍵,如果是一般索引的話,data便會指向對應的主索引。在B+樹的每一個葉子節點上面增加一個指向相鄰葉子節點的指針,就形成了帶有順序訪問指針的B+樹。其目的是提高區間訪問的性能。

3.InnoDB的B-樹非主碼

InnoDB中的非主碼索引使用了B-樹數據結構,但InnoDB中的B-樹結構實現和MyISAM中並不一樣。在InnoDB中,非主碼索引存儲的是主碼的實際值。而MyISAM中,非主碼索引存儲的包含主碼值的數據指針。這一點很重要。首先,當定義很大的主碼的時候,InnoDB的非主碼索引可能回更大,隨著非主碼索引數量的增加,索引之間大小差別可能會變得很大。另一個不同點在於非主碼索引當前可以包含主鍵的值,並且可以不是索引必須有的部分。

4.內存散列索引

在默認MySQL的引擎索引中,只有MEMORY引擎支持散列數據結構,散列結構的強度可以表示為直接鍵查找的簡單性,散列索引的相似度模式匹配查詢比直接查詢慢。也可以為MEMORY引擎指定一個B-樹索引實現。

5.內存B-樹索引

對於大型MEMORY表來說,使用散列索引進行索引範圍搜索的效率很低,B-樹索引在執行直接鍵查詢時確實比使用默認的散列索引快。根據B-樹的不同深度,B-樹索引在個別操作中的確可能比散列算法快。

6.InnoDB內部散列索引

InnoDB存儲引擎在聚簇B+樹索引中存儲主碼:但在InnoDB內部還是使用內存中的散列表來更高效地進行主碼查詢。這個機制有InnoDB存儲引擎來管理,用戶只能通過innodb_adaptive_hash_index配置項來選擇是否啟用這個唯一的配置選項。

深入了解MySQL的索引