MYSQL--浅析索引
索引是為了提高數(shù)據(jù)查詢的效率,類似于書的目錄。
索引的常見模型有三種:
1.哈希表:
只適用于等值查詢,不適用于范圍查詢
為什么呢?
哈希表是(key,value)的格式存儲,存儲的數(shù)據(jù)不一定是按照順序存的
比如user,有id,name,address三個屬性,用id%5作為哈希函數(shù)
現(xiàn)在存入3,2,1,4,7幾個id,如果我們要找id=2的user,2%5=2,很容易發(fā)現(xiàn)他在哈希表的第二個位置,但是id>2的不一定就存在第二個位置以后,比如id=6,6%5=1
那么如果位置沖突怎么辦?
上面已經(jīng)存入了id=2的user,現(xiàn)在要存入id=7的user,7%5=2,也要存在第二個位置
使用拉鏈法解決
2.有序數(shù)組:
更新慢,查詢快,查詢的時間復(fù)雜度是log(n)
但是如果更新,必須要移動更新位置之后的元素
所以有序數(shù)組適用于靜態(tài)的數(shù)據(jù)庫,或者更新很少的數(shù)據(jù)庫。
比如2015年的人口信息,數(shù)據(jù)不會再改變
3.二叉搜索樹:
更新,查詢的時間復(fù)雜度都是log(n)
一般不推薦使用二叉樹
比如一棵 100 萬節(jié)點的平衡二叉樹,樹高 20。一次查詢可能需要訪問 20 個數(shù)據(jù)塊。在機械硬盤時代,從磁盤隨機讀一個數(shù)據(jù)塊需要 10 ms 左右的尋址時間。也就是說,對于一個 100 萬行的表,如果使用二叉樹來存儲,單獨訪問一個行可能需要 20 個 10 ms 的時間,這個查詢可真夠慢的。為了讓一個查詢盡量少地讀磁盤,就必須讓查詢過程訪問盡量少的數(shù)據(jù)塊。那么,我們就不應(yīng)該使用二叉樹,而是要使用“N 叉”樹。這里,“N 叉”樹中的“N”取決于數(shù)據(jù)塊的大小。以 InnoDB 的一個整數(shù)字段索引為例,這個 N 差不多是 1200。這棵樹高是 4 的時候,就可以存 1200 的 3 次方個值,這已經(jīng) 17 億了。考慮到樹根的數(shù)據(jù)塊總是在內(nèi)存中的,一個 10 億行的表上一個整數(shù)字段的索引,查找一個值最多只需要訪問 3 次磁盤。其實,樹的第二層也有很大概率在內(nèi)存中,那么訪問磁盤的平均次數(shù)就更少了。
N叉樹中右邊的兄弟比左邊的兄弟值大
InnoDB的索引模型:
每一個索引在 InnoDB 里面對應(yīng)一棵 B+ 樹。
索引類型分為主鍵索引和非主鍵索引。主鍵索引的葉子節(jié)點存的是整行數(shù)據(jù)。在 InnoDB 里,主鍵索引也被稱為聚簇索(clustered index)。非主鍵索引的葉子節(jié)點內(nèi)容是主鍵的值。在 InnoDB 里,非主鍵索引也被稱為二級索引(secondary index)。
主鍵索引和普通索引有什么區(qū)別:
主鍵索引:select *?from user where id = 10,只用搜索id這顆二叉樹
普通索引:select * from user where name='張三',先搜索name這顆二叉樹中名字是張三的,再通過name這棵樹獲取到張三的id,去搜id這顆二叉樹,再獲取到全部信息。
去搜id這顆二叉樹的操作叫做回寫
索引維護:b+樹的合并,拆裂
索引什么時候使用自增主鍵,什么時候用自己的屬性?
自增主鍵的插入數(shù)據(jù)模式,正符合了我們前面提到的遞增插入的場景。每次插入一條新記錄,都是追加操作,都不涉及到挪動其他記錄,也不會觸發(fā)葉子節(jié)點的分裂。而有業(yè)務(wù)邏輯的字段做主鍵,則往往不容易保證有序插入,這樣寫數(shù)據(jù)成本相對較高。
?
主鍵長度越小,普通索引的葉子節(jié)點就越小,普通索引占用的空間也就越小。所以,從性能和存儲空間方面考量,自增主鍵往往是更合理的選擇。
有沒有什么場景適合用業(yè)務(wù)字段直接做主鍵的呢?還是有的。比如,有些業(yè)務(wù)的場景需求是這樣的:只有一個索引;該索引必須是唯一索引。這就是典型的 KV 場景。由于沒有其他索引,所以也就不用考慮其他索引的葉子節(jié)點大小的問題。這時候我們就要優(yōu)先考慮上一段提到的“盡量使用主鍵查詢”原則,直接將這個索引設(shè)置為主鍵,可以避免每次查詢需要搜索兩棵樹。
?
回到主鍵索引樹搜索的過程,我們稱為回表。
那么有沒有什么方法可以避免回表呢??
1.覆蓋索引:
select id from user where name='張三'
這種的我們可以發(fā)現(xiàn),只需要查找user,那么通過找name這顆二叉樹獲得id就行,不用回寫。
類似上面的過程就叫做覆蓋索引
2.最左前綴:聯(lián)合索引的最左 N 個字段,也可以是字符串索引的最左 M 個字符
3.聯(lián)合索引:根據(jù)創(chuàng)建聯(lián)合索引的順序,以最左原則進行where檢索,比如(age,name)以age=1 或 age= 1 and name=‘張三’可以使用索引,單以name=‘張三’ 不會使用索引,考慮到存儲空間的問題,還請根據(jù)業(yè)務(wù)需求,將查找頻繁的數(shù)據(jù)進行靠左創(chuàng)建索引。
4.索引下推:like 'hello%’and age >10 檢索,MySQL5.6版本之前,會對匹配的數(shù)據(jù)進行回表查詢。5.6版本后,會先過濾掉age<10的數(shù)據(jù),再進行回表查詢,減少回表率,提升檢索速度
總結(jié)
以上是生活随笔為你收集整理的MYSQL--浅析索引的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Leetcode--80. 删除排序数组
- 下一篇: Oracle 数据库