正確的理解MySQL的索引機制以及內部實現(二)
如果覺得對你有幫助,能否點個贊或關個注,以示鼓勵筆者呢?!博客目錄 | 先點這裏
- 第一部分 傾向於MySQL數據庫索引的日常生活,主要體現MySQL索引的應用
正確的理解MySQL的索引機制以及內部實現(一) - 第二部分 更傾向於講解MySQL B+樹索引的實現原理
正確的理解MySQL的索引機制以及內部實現(二)
因爲數據庫索引的知識點比較多,而且感覺比較複雜和混亂!所以爲了讓文章更加的清晰,最終在按原目錄結構寫了三分之二的時候,還是決定分爲兩個部分分開去描述(雖然還是有很多地方沒有去解釋)
- 前提概要
- 基礎數據結構
- B樹和B+樹
- 索引的一些概念
- 主鍵索引和輔助鍵索引
- 聚簇索引與非聚簇索引
- 稠密索引和稀疏索引
- 覆蓋索引
- InnoDB和MyISAM下的索引
- InnoDB下的B+Tree索引
- MyISAM下的B+Tree索引
- 物理空間角度理解不同引擎下的數據存儲
- InnoDB、MyISAM下索引實現的區別和優缺點
- 關於聚簇索引容易混淆的小貼士
- 索引的其他底層實現
- 哈希索引和BitMap索引
- 倒排索引
- 索引名詞混亂的現狀
- 對於索引名詞混亂的個人感受
- 容易混淆的索引名詞概念
前提概要
基礎數據結構
在學習MySQL的索引之前,我們很有必要先知道一個數據結構知識。
- 二分搜索樹
初入數據結構的二叉搜索樹以及Java實現 - 平衡二叉樹
初入數據結構中的平衡二叉搜索樹(AVL樹)及Java實現 - B樹,B+樹
初入數據結構中的B類樹(B Tree , B+ Tree)
可以說,如果不知道這三個數據結構的情況下,硬啃MySQL索引是很喫力的,也不好理解。
因爲一篇博客的篇幅有限,我也不想寫成兩三萬字的大長文,所以有需要的朋友,可以從上面的子鏈看看這三個數據結點的簡介和概念再回到本文繼續瀏覽
B樹,B+樹
畢竟B類樹是構造MySQL數據庫索引的底層實現(準確的說是B+樹
),所以本文還是要略帶的介紹一下的。
什麼是B樹?
B樹,又名B-樹(B減樹
)。它是一棵多路平衡多路查找樹。它具有一些索引結構的特性
- 一個結點可以存儲多個數據
- 一個結點可以有多個孩子
- 自平衡,所有葉子結點都處於同一個層次
總之,使用B樹作爲索引的存儲結構,可以大幅的降低樹的高度,保持一棵"矮胖樹"
的特性, 降低磁盤IO操作,提高數據庫查詢性能
什麼是B+樹?
那什麼是一棵B+樹呢?B+樹說白了就是B樹的變種,也是一棵平衡多路查找樹,但分別結合了B樹和索引順序訪問的優勢,更適合成爲數據庫索引的底層實現
- 所有非葉子結點只作爲中間結點,存放指針地址,不存放直接的數據,所有數據存放在葉子結點上
- 葉子結點中的所有數據都帶有指向上一個,下一個數據的指針,實際雙向鏈表結構,可以實現雙向順序訪問
總而言之就是,B+樹綜合了B樹的優點,還帶有順序索引的功能,更加的牛逼
B+樹爲什麼替換了B樹稱爲MySQL索引的底層實現?
B+樹的磁盤讀寫代價更低
因爲B+樹的中間結點存儲的都是索引數據,僅僅是一個地址,並非直接的數據,所以同一個結點中(同一個磁盤頁大小),B+樹可容納的關鍵字數會比B樹更多(因爲一個簡單的地址幾乎肯定小於一個直接的數據)。所以同樣的數據量下,B+樹會比B樹更加“矮胖”,樹高更小,所以查詢時需要的IO次數就更少B+樹的查詢效率更加穩定
因爲B+樹的所有元素都存儲在葉子結點中,而葉子結點都屬於同一層級,每一個B+樹查詢都是從根結點遍歷到葉子結點的過程,所以不管查詢什麼,時間複雜度相比B樹查詢都更加的穩定和近似。B+樹更有利對數據的掃描
B樹中雖然解決了查詢的效率,但是如果需要查詢一串相鄰的數值,有可能需要回溯來回掃描或是從根結點多次中序遍歷。而B+樹的所有元素都存儲葉子結點,每個葉子結點都有指向下一個結點的指針,直接線性遍歷即可。同樣B+樹也更加的利於做範圍查詢
如果想要知道數據庫索引的底層實現是怎麼從二叉搜索樹->平衡二叉搜索樹->B樹->B+樹
的演進過程的也可以看這篇文章初入數據結構中的B類樹(B Tree , B+ Tree)
索引的一些概念
主鍵索引和輔助鍵索引
(一)主鍵索引(Primary Index)
主鍵索引
(primary index
)
主鍵索引又稱主索引
以表的主鍵(primary key
)創建的索引樹,我們就稱其爲該表的主鍵索引
(二)輔助鍵索引(Secondary Index)
輔助鍵索引
(secondary index
)
輔助鍵索引,又稱輔助索引
,次級索引
,二級索引
輔助索引以表的非主鍵的字段創建的索引樹,我們就稱其爲該表的輔助鍵索引
簡而言之,如果將一張表的所有字段都單獨建立一個索引,那麼除了以主鍵生成的索引外,其他都屬於輔助鍵索引。 其實輔助鍵索引更常叫輔助索引,只是我爲了對應主鍵索引,還是叫輔助鍵索引能更讓人容易理解,不容易混亂。
聚簇索引和非聚簇索引
- 聚簇是爲了提高某個屬性(或屬性組)的查詢速度,把這個或這些屬性(稱爲聚簇碼)上具有相同值的元組集中存放在連續的物理塊。
(一)聚簇索引(Clustered Index)
什麼是聚簇索引?
- 聚簇索引又稱
聚集索引
。我們將根據鍵值對數據庫表中的數據進行排序存儲,並將相關的信息聚簇在一起索引就叫聚簇索引(該順序是物理上連續的存儲空間的順序) - 針對MySQL而言,聚簇索引只存在於InnoDB中,再具體些,如果有主鍵,一般指代的是InnoDB每個表的主鍵索引
聚簇索引的特性
-
聚簇索引定義了數據存儲在表中的順序,該表的數據有且僅以一種方式排序。因此,每個表只能有一個聚簇索引。在RDBMS中,在存在主鍵的情況下,主鍵索引就是該聚簇索引
-
聚簇索引其中一個大特徵就是將索引和數據存儲在同一個文件中,既葉子結點不僅保存鍵的信息,還保存了位於同一行其他列的信息,簡而言之,聚簇索引的葉子結點保存的是一個完整行記錄數據
-
同時我們也能知道聚簇索引是一種有序索引,它的具體實現可以是稠密索引,也可以是稀疏索引
那些索引屬於聚簇索引?
- InnoDB和MyISAM之間,只有InnoDB支持聚簇索引
- 若一張表存在主鍵,則以該主鍵列生聚簇索引樹
- 若一張表沒有主鍵,則MySQL會找到該表的第一個唯一非空列的索引作爲聚簇索引
- 如以上條件皆不滿足,InnoDB會在內部生成一個名爲
GEN_CLUST_INDEX
隱式聚簇索引。該索引是基於一個名爲DB_ROW_ID
的隱藏字段,通常稱之隱式主鍵。
爲什麼InnoDB存儲引擎一定要有聚簇索引呢?
- 因爲如果我們的SQL條件是一個非主鍵列的數據,那麼在底層索引查詢中,很可能需要跨樹查詢,既兩次查詢。
- 既InnoDB的輔助鍵索引的葉子結點並不存儲行數據,而條件值對應的該主鍵值。然後我們需要根據輔助鍵索引查詢到的主鍵值,再去聚簇索引中查詢所以非主鍵索引包含兩次查找,一次是查找次級索引自身,然後能再查找主鍵
(二)非聚簇索引(Non-
什麼是非聚簇索引?
- 非聚簇索引將數據存儲在一個位置,將索引存儲在另一個位置,索引包含指向該數據位置的指針。這樣的一個索引就是非聚簇索引,一個表中可以包含多個非聚簇索引
非聚簇索引的特徵
- 非聚簇索引是一個與聚簇索引想向的概念。針對MySQL而言,可以說InnoDB的輔助鍵索引,以及MyISAM的主、輔索引都是非聚簇索引
- 非聚簇索引只存儲鍵與指針,不存儲數據,所以非聚簇索引的葉子結點僅保存數據的地址(
MyISAM
)或是其主鍵信息(InnoDB
)。 - 使用非聚簇索引進行查詢,最終會定位到葉子結點,得到數據地址或主鍵信息,。然後還要根據獲得的地址或主鍵信息進一步定位到數據,通常作爲中間人的作用。
那些索引屬於非聚簇索引
- 說白了,InnoDB下的輔助鍵索引和MyISAM下的主、輔鍵索引都屬於非聚簇索引,僅僅只有InnoDB下的主鍵索引(唯一非空列索引…之後細節忽視)才屬於聚簇索引
稠密索引和稀疏索引
引用至:
@difference between sparse index and dense index - @stackoverflow
@Indexing in Databases | Set 1 - @GeeksForGeeks
Ordered
Indexing is of two types:
- Dense Index
- Sparse Index
.
Dense Index :
An
index record appears for every search key value in file.This record
contains search key value and apointer to the actual record..
Sparse Index :
- Index records are created only for some of the records.
- To locate a record, we find the index record with the largest search key value less than or equal to the search key value we are looking for.
- We start at that record pointed to by the index record, and proceed along the pointers in the file (that is, sequentially) until we find the desired record.
說白了,稠密索引和稀疏索引屬於有序索引(ordered index)
的一個分類
稠密索引:
- 稠密索引的真實數據是按順序儲存的
- 爲每一個鍵都創建一個索引記錄
- 每個索引記錄都包含鍵本身和指向實際數據的指針
- 因爲每個鍵都有索引,所以可以直接通過索引就找到目的鍵對應的數據
稀疏索引:
- 稀疏索引的真實數據是按順序存儲的
- 只爲部分的鍵創建索引記錄
- 當在稀疏索引中查找某個目的鍵時,通常會通過索引,先找到小於或等於目的鍵的其他鍵的數據項,既通過索引找到比目的鍵值要小的數據項(如果目的鍵有索引,就直接找到目的鍵的數據)。然後在數據項按順序遍歷(線性),直到找到目的鍵的數據記錄。
稀釋索引怎麼找目的數據?
- 要找字段值爲
1003
的數據,就要先找到小於或等於1003
的鍵,比如1001
。 - 通過
1001
的索引,我們找到1001
所在的行數據,然後線性向下遍歷兩次,我們就找到了1003
所在的行數據啦! - 這也是稠密和稀疏索引的前提,就是有序
稠密索引和稀疏索引的優缺點
- 相對某列鍵而言,稠密索引對每個數據都建有索引,要查詢起來,直接快速。但是因爲要爲每個數據都建立對應的索引,所以需要比較大的空間資源
- 而稀疏索引因爲只針對部分數據建立索引,所以空間資源佔用小,但是查詢效率相對比較慢
Clustered index is dense or sparse?
覆蓋索引
覆蓋索引(covering index
),也稱爲索引覆蓋。其實我更想稱其爲索引覆蓋,以爲我理解的覆蓋更像是一個動詞。因爲覆蓋索引其實並不是一種索引類型,而是一個技術性的提升查詢效率的機制。
什麼是覆蓋索引?
- 既在InnoDB中,只需要從輔助鍵索引中就可以查詢到最終想要的數據結果,而不需要再從聚簇索引中二次查詢。這麼的一個技術手段,我們就稱之爲覆蓋索引
- 覆蓋索引在MySQL中,僅僅是針對InnoDB存儲引擎而言的。準確的說,是針對聚簇索引和非聚簇索引共存的情況下才能起作用的
- 覆蓋索引並不是一種索引類型,而是一種技術手段
舉個應用覆蓋索引的粟子!
在InnoDB存儲引擎的表中:
- 比如我們在某個表建立了一個普通組合索引
(col1,col2,col3)
,由三個列組成。那麼我們的select col1,col2,col3 from table where col1 = xxx;
語句肯定會有覆蓋索引的技術加持。只進行了一次(col1,col2,col3)
輔助鍵索引,我們就可以得到(col1,col2,col3)
三列數據的結果,自然也就不需要再拿到相關數據的主鍵,再跑到聚簇索引二次查詢 - 比如我們在某個表,以col1字段建議一個普通索引,那麼我們的
select col1 from table where col1 = xxx;
, 也會得到覆蓋索引的技術加持。
InnoDB和MyISAM下的B+樹索引
InnoDB下的B+樹索引
(一) 樣例表
create table `student_innodb` (
`sid` int(11) not null ,
`name` varchar(20) not null ,
`age` int(11) not null ,
`tel` varchar(11) not null ,
`email` varchar(20) not null ,
`class` varchar(20) not null ,
primary key (`sid`),
unique name(`name`),
index age(`age`),
index tel_email(`tel`,`email`)
) engine=innodb default charset=utf8;
(二) InnoDB的表數據存放在哪?
我們知道,MySQL下的索引根據以列屬性進行分類,可以分爲主鍵索引
和輔助鍵索引
。在InnoDB下,主鍵索引採用的是聚簇索引,輔助鍵索引採用的是非聚簇索引。
- 主鍵索引的葉子結點的每個關鍵字對應的數據,存放的都是完整的行數據
- 輔助鍵索引的葉子結點的每個關鍵字對應的數據,存放的都是主鍵信息
InnoDB的數據實際存儲在哪?
- 我們知道InnoDB的主鍵索引就是聚簇索引,聚簇索引的葉子結點存放的都是完整的數據。這就很容易的推斷出,一張表的主鍵索引就已經一字不差的存放了整張表的所有數據。既該索引文件也是該表的直接數據存儲文件
- 既InnoDB下,一張表的所有數據都是存放在該表的聚簇索引葉子結點中的。
(三) InnoDB下利用索引查詢的過程
下圖爲InnoDB下的走索引查詢的過程
主鍵查詢
- 通過主鍵查詢數據,
select * from student_innodb where sid = 1;
- 直接走主鍵索引,從主鍵索引的根結點開始遍歷,然後查到葉子結點,直接得到行數據
其他字段索引的查詢
- SQL條件不是主鍵,而是其他建立了索引的字段,假設是name。
select * from student_innodb where name = 'jerry';
- 首先查詢以name字段建立的索引,該索引屬於輔助鍵索引。所以從該name字段索引的根結點開始遍歷,直到找到葉子結點,得到
name = 'jerry'
的行記錄的主鍵信息sid = 1
- 然後通過得到
sid = 1
的主鍵信息去主鍵索引中再次遍歷,從根結點開始,直接葉子結點,便得到了行數據本身
所以,我們知道在InnoDB中,查詢條件是主鍵的索引查詢,只需要遍歷一次索引樹,而非主鍵的條件,這需要兩次,先遍歷輔助鍵索引得到對應的主鍵信息,再通過主鍵信息在主鍵索引中遍歷,得到行數據
MyISAM下的B+樹索引
(一) 樣例表
create table `student_myisam` (
`sid` int(11) not null ,
`name` varchar(20) not null ,
`age` int(11) not null ,
`tel` varchar(11) not null ,
`email` varchar(20) not null ,
`class` varchar(20) not null ,
primary key (`sid`),
unique name(`name`),
index age(`age`),
index tel_email(`tel`,`email`)
) engine=myisam default charset=utf8;
(二) MyISAM的表數據存放在哪?
我們知道,MySQL下的索引根據以列屬性進行分類,可以分爲主鍵索引
和輔助鍵索引
。在MyISAM下,主鍵索引和輔助鍵索引都屬於非聚簇索引。
- 非聚簇索引的葉子結點的關鍵字的值都是對應數據在數據文件中的地址
- 所謂地址,就是葉子結點存儲的不是數據本身,而僅僅是一個指針
MyISAM的數據實際存儲在哪?
- 既MyISAM存儲引擎的數據文本和索引是分開存儲的,索引是索引,索引的葉子結點存儲的也僅僅是指針
- MyISAM下的表數據都是單獨存儲一個文件進行存儲的,並不像InnoDB一樣,存儲在主鍵索引中,所以MyISAM不管查詢是走主鍵索引,還是輔助鍵索引,通通都要遍歷到葉子結點,從葉子結點獲得真實數據的地址,再通過地址找到真實數據。
(三) MyISAM下利用索引查詢的過程
下圖爲MyISAM下的走索引查詢的過程
通過主鍵查詢:
- 通過主鍵查詢數據,
select * from student_innodb where sid = 1;
- 直接走主鍵索引,從主鍵索引的根結點開始遍歷,然後查到葉子結點,得到行數據在數據文件中的地址
- 通過地址,找到數據文件中的目的行數據
通過其他非主鍵字段查詢:
- SQL條件不是主鍵,而是其他建立了索引的字段,假設是name。
select * from student_innodb where name = 'jerry';
- 首先查詢以name字段建立的索引,該索引屬於輔助鍵索引。所以從該name字段索引的根結點開始遍歷,直到找到葉子結點,得到目的行記錄在數據文件的地址
- 通過地址,找到數據文件中的目的行數據
所以,我們知道在MyISAM中,查詢不管是走主鍵索引,還是非主鍵索引,在葉子結點得到的都是目的數據的地址,還需要通過該地址,才能在數據文件中找到目的數據(只需要一次遍歷和一次的地址訪問)
物理空間角度理解不同引擎下的數據存儲
(一) InnoDB的數據文件
我們創建一個名爲student_innodb
的表,存儲引擎使用InnoDB, 然後在搜索電腦中存放student_innodb
表數據文件的地方
可以看到兩個文件,student_innodb.frm
和student_innodb.ibd
。熟悉的人肯定知道,這兩個文件就是student_innodb表的表定義文件和數據文件
student_innodb.frm
.frm文件是一份定義文件,也就是定義student_innodb
表是一張怎麼樣的表student_innodb.ibd
.ibd文件則是該表的索引,數據存儲文件,既該表的所有索引樹,所有行記錄數據都存儲在該文件中
總之,我們可以知道,InnoDB的表,數據存儲文件只有一個,既.ibd
文件
(二) MyISAM的數據文件
我們創建一個名爲student_myisam
的表,存儲引擎使用MyISAM, 然後在搜索電腦中存放student_myisam
表數據文件的地方
我們可以看到三個文件, student_myisam.frm
, student_myisam.MYD
和student_myisam.MYI
文件。上面我們分析過了。.frm
文件是表定義文件,不是數據文件。所以我們只關注MYD和MYI結尾的文件。
student_myisam.MYD
.MYD
文件是MyISAM存儲引擎表的所有行數據的文件student_myisam.MYI
.MYI
文件存放的是MyISAM存儲引擎表的索引相關數據的文件
總之,我們可以簡單的得出結論,MyISAM引擎下,表數據和表索引數據是分開存儲的。
(三) 總結
- MyISAM存儲引擎中的表數據和表索引數據是分開文件進行存儲的
- InnoDB存儲引擎中的表數據和表索引數據是在同一個文件存儲的
- 這也讓我們更好的理解,爲什麼說InnoDB引擎下,整個表數據是存儲在該表的聚簇索引樹上的。
InnoDB、MyISAM下索引實現的區別和優缺點
InnoDB,MyISAM B+Tree索引模型的區別和優缺點對比,在廣義上的角度,問題可以切換成聚簇索引和非聚簇索引的優缺點對比。因爲InnoDB和MyISAM的B+Tree索引機制,很大程度上的區別,就是一個支持聚簇索引,一個不支持
(一) 聚簇索引的優缺點
聚簇索引的優點
- 聚簇索引可以將相關的數據緊密的關聯起來,存儲在相鄰的連續物理空間,利於範圍查詢,比如將相關的數據存放在一個葉子結點上,既一個結點的多個關鍵字對應的數據都存儲在一個數據頁中,範圍查詢時,磁盤一次Load出即可,降低IO操作次數,比如針對
MAX, MIN, COUNT
等聚集函數都有很好的作用。 - 聚簇索引將數據和索引存儲在同一個數據文件。 既聚簇索引的葉子結點不僅存放鍵的信息,還存儲相關其他列的完全數據。當查詢走聚簇索引,不需要中間人跳轉,直接就可以獲得目的數據,查詢效率更快
聚簇索引的缺點
- 因爲聚簇索引是順序存儲的,如果多次的插入操作是以非順序的方式執行,那麼最終聚簇索引需要不斷的維護這個順序,這是需要一定性能消耗的。
- 當聚簇索引中的主鍵發生更改時,可能需要重新維護順序,迫使物理空間的交換,所以聚簇索引需要更長的時間來更新記錄
- 支持聚簇索引的存儲引擎的輔助鍵索引的查詢結果只是一箇中間結果,還需要通過中間結果到聚簇索引上二次查詢,操作相對繁瑣
(二) 非聚簇索引的優缺點
非聚簇索引的優點
- 因爲一張表只能有一個聚簇索引,而非聚簇索引則可以有多個。所以非聚簇索引允許我們對一張表建立多個索引,提高數據庫的查詢性能
- 非聚簇索引佔用空間小,因爲葉子結點不存儲真實數據,所以非聚簇索引相比聚簇索引更小。
- 在部分查詢中,可以利用覆蓋索引的特性,加快查詢速度,直接從輔助鍵索引中獲得想要的數據,而不需要做二次查詢。
- 非聚簇索引只需要一次遍歷,便可得到數據地址。支持聚簇索引的存儲引擎會導致其輔助鍵索引查詢的結果只是一箇中間結果,還需要通過該中間結果在聚簇索引再遍歷一次。而不支持聚簇索引的存儲引擎,只有非聚簇索引,非聚簇索引只需要一次遍歷,即可得到真實數據的地址
非聚簇索引的缺點
- 非聚集索引只能按邏輯順序存儲數據,並不允許以物理空間連續的方式對數據行進行順序存儲。既非聚簇索引一個葉子結點內部的所有關鍵字僅僅是邏輯順序的維護。一個結點對應真實數據在數據文件中可能並非按連續物理空間存儲的。 相對聚簇索引的查詢,IO次數可能更多,查詢性能更低
- 相比聚簇索引,範圍查詢更慢,因爲聚簇索引的範圍查詢可以讓磁盤一次load出整個結點的數據線性遍歷。雖然非聚簇索引的同葉子結點之間的關鍵字也是邏輯順序存儲,也可以線性遍歷,但每線性遍歷一個關鍵字都需要中間再跳轉到另一個地方(InnoDB下的聚簇索引)遍歷或(MyISAM下的數據文件)訪問 。這個中間過程實際都是不同的IO操作,可能觸發磁盤不同盤塊的數據讀取。所以本質還是會造成大量的IO操作。
- 每當聚簇索引的主鍵值更新時,可能會觸發非聚簇索引的更新,因爲非聚簇索引的葉子結點可能存放的是主鍵信息(比如InnoDB)
- 每當數據文件中的數據發生更新時, 也可能會觸發非聚簇索引的更新,因爲可能會導致非聚簇索引葉子結點的數據地址發生改變(比如MyISAM)
關於聚簇索引容易混淆的小貼士
我知道很多情況下,有的朋友在看了一些書籍或博客之後,會有一種認知傾向,認爲InnoDB的索引採用的就是聚簇索引,而MyISAM的索引採用的是非聚簇索引的方式。雖然可以這麼說,但其實這個概念也並非完全正確。
- 因爲索引是針對存儲引擎纔有意義的,而針對MySQL的存儲引擎來說,準確的說,是InnoDB支持聚簇索引的概念,而聚簇索引的概念則體現在InnoDB的主鍵索引或其他特殊索引上。因爲InnoDB支持聚簇索引,所以InnoDB可以將數據和索引存儲在同一個文件。
- 在細粒度的角度上考慮,是InnoDB不僅採用聚簇索引,也採用了非聚簇索引,因爲在InnoDB中,主鍵索引屬於聚簇索引,葉子結點不僅包含鍵值,還包含行中其他列的數據。而其輔助鍵索引則屬於非聚簇索引,因爲輔助鍵索引的葉子結點只包含鍵值以及主鍵數據。通過輔助鍵索引遍歷之後得到主鍵信息,然後還要通過主鍵再在主鍵索引遍歷一次,才能得到行數據。
- MyISAM則是不管主鍵索引還是輔助鍵索引都屬於非聚簇索引
所以總的來說,在廣義上,通俗的角度來說,的確可以說InnoDB採用的是聚簇索引,MyISAM採用的是非聚簇索引。但更準確的說法是,InnoDB支持聚簇索引,MyISAM不支持聚簇索引
針對此文,最好可以看看官網對Clusered Index
和 Secondary Index
的解釋@Clustered and Secondary Indexes - @MySQL 官網
索引的其他底層實現
哈希索引
MySQL支持哈希索引,但是侷限於部分的存儲引擎,既MEMORY/HEAP和NDB。而常見的InnoDB和MyISAM則並不支持。
- 雖然InnoDB不支持哈希索引,但是它依然有曲線救國的手段,就是支持一種僞哈希索引的方式,變相支持哈希索引。
- 這樣的僞哈希索引,我們叫它爲自適應哈希索引。但這個自適應哈希索引並不是由我們人爲控制建立的。而InnoDB存儲引擎引擎自動優化創建,不受人爲干預的
- 但是我們可以通過參考來確認InnoDB是否開啓自適應哈希索引模式
什麼是自適應哈希索引?
- 什麼是哈希表,相信我們大家都知道,通過O(1)的時間複雜度,我們就可以查詢到想要的數據,但是需要付出O(n)的空間複雜度代價。這也是InnoDB不支持哈希索引的原因之一
- 那麼什麼是自適應哈希索引呢?說白了,它也是哈希索引,但是它不爲表中的所有數據都建立索引。而是有選擇性的爲一些熱點數據建立哈希索引。
- 既Innodb存儲引擎會監控對某表的輔助鍵索引查找情況,如果發現某輔助鍵索引被頻繁訪問,既代表某些關鍵字是熱數據,於是這些數據則會被放入哈希索引中,由此讓特定頻繁被訪問的熱點數據可以享受到哈希索引O(1)的速度。
至此,我們可以知道InnoDB並不支持我們自建哈希索引,但是在某些情況下哈希索引的效率的確很高,於是InnoDB自己就爲熱點數據維護一套哈希索引,因爲這套哈希索引並不是爲所有數據建立的,而是由InnoDB動態監控,自行維護的,爲部分熱點數據優化速度而生。所以又名自適應哈希索引,以示區別。既自適應哈希索引是存儲引擎自身的優化手段,並非提供出來給用戶使用的索引類型。
相比B+Tree索引,哈希索引有什麼缺陷?
- 哈希索引也沒辦法利用索引完成排序
- 不支持最左匹配原則
- 存在大量哈希衝突的情況下,哈希索引的效率也是極低的
- 不支持範圍查詢
倒排索引
我們知道MySQL的InnoDB曾經是不支持MyISAM所獨有的全文索引的。但是MySQL 5.6之後,InnoDB也支持全文索引FULLTEXT
了。
- 說是全文索引,其實它只代表可以實現全文檢索的功能,而全文檢索的底層實現,實際就是倒排索引,所以你也可以把全文索引的本質,當做是倒排索引。再瞭解全文檢索之前,務必要先了解倒排索引
爲什麼叫倒排索引?
- 因爲英文單詞Inverted有顛倒的意思,然後可能就被翻譯爲倒排索引,也有很多地方叫反向索引。相對而言的索引就是正排索引(forward index)
- 倒排索引和正排索引,我的個人理解是,它與我們之前說的B+索引,哈希索引的應用不同。拿這些索引的知識去理解正排索引和倒排索引,感覺有些難以聯繫起來,容易混亂。因爲正排,倒排是屬於搜索引擎範疇的概念,所以理解正排,倒排最好還是先對搜索引擎有一些瞭解。比如使用過ElasticSearch
什麼是倒排索引(Inverted index)?
說實話,倒排索引也不是一個簡單的概念,很多搜索引擎的底層原理都是倒排索引,比如ElasticSearch等。
學習倒排索引的時候,最好還是需要一些搜索引擎的知識會更容易理解。
倒排索引就是相對正排索引相反而言的模型。正排索引是通過文檔ID來遍歷文檔內容,找到關鍵字(文檔 -> 關鍵字)。而倒排索引則是通過關鍵字,找到所在的文檔(關鍵字 -> 文檔)
以上正排索引,假如我們的搜索引擎是基於正排索引實現的,那麼我們要在索引庫中查詢"python"
關鍵字, 就很可能需要一個一個文檔的進行遍歷,直到在某個文檔的內容中找到"python"
單詞。這樣的一個時間複雜度是很大的,尤其是數據量很大的情況下。所以基於正排索引實現的搜索引擎是不現實的
如果在每一文檔錄入搜索引擎索引庫的時候,我們就對文檔的內容進行分詞,統計,分析。建立倒排索引,記錄分詞得到的每個單詞對應文檔的出現位置和出現次數。 那麼我們在搜索引擎查詢"python"
關鍵字,就會非常的快速,只需要通過關鍵字就可以馬上查詢到已經預處理的統計分析結果。也就知道了'python'
關鍵字在文檔A和文檔B出現過。展示給用戶即可。
這也是爲什麼是正排和倒排的原因,正排是通過文檔查找關鍵字,倒排是通過關鍵字查到對應的文檔。詳細的倒排索引知識以後有時間再在ES的知識點中重點說明。
什麼是倒排索引? - @作者:返回主頁 大數據和人工智能躺過的坑
倒排索引爲什麼叫倒排索引?- @知乎
索引名詞混亂的現狀
對於索引名詞混亂的個人感受
說實話呀,索引的概念就跟數據庫的鎖概念一樣,四處充斥着各種各樣的說法,各種各樣的名詞。對於初學者來說,十分的混淆。反正我整理本文時的心情是非常複雜的,所以我不能絕對的說,我表達的觀點一定是正確的,但我努力讓它是正確的。針對這樣混亂的現象,我個人的感受是:
- 數據庫的設計和實現源於國外,文獻是英文的。而針對同一個英文單詞,可以由多個不同的中文單詞去解釋,比如聚集,聚簇的英文都可以是clustered。所以我揣測在文獻資料翻譯的過程中,因爲作者的多元化,所以導致翻譯結果也多元。最終導致針對同一名詞,有着很多的中文單詞描述
- 國內的文獻資料缺乏權威,網絡資料質量參差不齊,錯誤的解釋,一傳十,十傳百,形成習慣後,錯誤就成爲了一種政治正確,最終導致國內含義和國外含義的不同
- 概念複雜抽象,因爲技術視野的侷限性,很容易對概念造成錯誤的理解(比如我)。比如一些情況下,會有標準和實現的區分,標準只是一個模板,而實現纔是真正的體現。也有一些情況下,他們是不同維度下概念,雖然有着相同或類似的名詞,但實際表達着不同緯度的含義。
- 還有一點的就是,數據庫的具體實現衆多,比如SQL Server,MySQL,PgSQL,Oracle等。 不同的關係型數據庫之間,對於同一含義,可能存在不同的名詞。
以上只是我的個人感受,如果因爲是我的自身侷限性導致將正確的結果誤以爲是一種混亂,希望大家告知!萬分感謝
容易混淆的索引名詞概念
爲了避免概念的混淆,我將自己認爲是正確的說法,描述一下,大致從三個方向進行分類
這裏對數據庫的各類索引解釋的比較齊全
(一)數據索引底層實現原理
B樹索引
以B樹作爲底層數據結構而構成的索引樹,就叫B樹索引B+樹索引
以B+樹作爲底層數據結構而構成的索引樹,就叫B+樹索引BitMap索引
以BitMap作爲底層數據結構而構成的索引樹,就叫BitMap索引Hash索引
以哈希表作爲底層數據結構而構成的索引樹,就叫Hash索引
(二)數據庫支持的功能性索引
單列索引:
主鍵索引
以主鍵創建的索引,都叫主鍵索引唯一索引
以唯一值創建的索引都叫唯一所以,主鍵索引也屬於唯一索引的一種普通索引
非主鍵,非唯一字段創建的索引都是普通索引,比如根據可重複的列創建的索引全文索引
用於實現全文檢索的索引模式
多列索引:
組合索引
將多個列的字段,組合起來,形成組合索引樹
(三)數據庫索引的內部實現的概念
主輔區分:
主鍵索引
(primary index
)
主鍵索引又稱主索引
以表的主鍵(primary key
)創建的索引樹,我們就稱其爲該表的主鍵索引
輔助鍵索引
(secondary index
)
輔助鍵索引,又稱輔助索引
,次級索引
,二級索引
輔助索引以表的非主鍵的字段創建的索引樹,我們就稱其爲該表的輔助鍵索引
聚簇區分:
聚簇索引
(clustered index
)
聚簇索引又稱聚集索引
。針對MySQL而言,聚簇索引只存在於InnoDB中,再具體些,指代的就是InnoDB每個表的主鍵索引非聚簇索引
(non-clustered index
)
非聚簇索引只是與聚簇索引想向的概念。針對MySQL而言,可以說InnoDB的輔助鍵索引,以及MyISAM的主、輔索引都是非聚簇索引
稠密區分:
準確的說,是 有序索引
(ordered Index
)可以分爲稠密索引和稀疏索引兩類
稠密索引
(dense index
)
稠密索引,有的地方又稱密集索引
。稠密索引是指會爲每一個數據都建立一個索引稀疏索引
(sparse index
)
稀釋索引是指只爲部分的數據建立索引,通過索引先找到比目的數據要小的數據,然後順序查找
(四)總結一下
- 聚簇索引有些地方也稱聚集索引
輔助鍵索引(Secondary Index)
通常稱爲輔助索引,有時也稱爲二級索引,次級索引主鍵索引(Primay Index)
在InnoDB引擎下,有時候它與聚簇索引(Clusered Index)
是等價的。- 在
主鍵索引(Primay Index)
和聚簇索引(Clusered Index)
等價的情況下,例如InnoDB, 與主鍵索引(聚簇索引)相對的輔助鍵索引(輔助索引(Secondary Index)
)就是非聚簇索引(Non-Clusered Index)
- 因爲聚簇索引(
Clusered Index
)在InnoDB下又是一種有序索引(Ordered Index
),所以聚簇索引又可以有具體的採用形式,可以是稠密索引形式(Dense Index
),也可以是稀疏索引形式(Sparse Index
)。
總而言之,中文博大精深,名詞多樣化,如果要得知一個名詞最精確的含義,建議還是得知道它的英文名詞。這一點在數據庫索引具體實現內部分類
的名詞中最容易產生混淆,切記切記。然後根據不同的角度,又可以得到很多的分類,有些概念的邊界也的確很難找,我也不想深究了,畢竟都快咬文嚼字了,這種感覺煩的很。
參考資料
-
《MySQL技術內幕》
-
difference between sparse index and dense index - @stackoverflow
-
Clustered vs Non-clustered Index: Key Differences with Example - @guru99 (推薦!!)
-
如果覺得對你有幫助,能否點個贊或關個注,以示鼓勵筆者呢?!