mysql 聚簇索引和非聚簇索引_图文并茂,说说MySQL索引
點擊上方?小偉后端筆記?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達作者:小小木的博客來源:cnblogs.com/wyc1994666/p/10831039.html
序
開門見山,直接上圖,下面的思維導圖即是現在要講的內容,可以先有個印象~
- 常見索引類型(實現層面)
- 索引種類(應用層面)
- 聚簇索引與非聚簇索引
- 覆蓋索引
- 最佳索引使用策略
1.常見索引類型(實現層面)
首先不談Mysql怎么實現索引的,先馬后炮一下,如果讓我們來設計數據庫的索引,該怎么設計?
我們首先思考一下索引到底想達到什么效果?其實就是想能夠實現「快速查找」數據的策略,所以索引的實現本質上就是一個「查找算法」。
但是跟普通的查找有所不同,因為我們的數據有以下特征:
「1.存儲的數據是非常非常多的」「2.并且還不斷的動態變化」
所以實現索引時需要考慮到這兩個特點。我們需要找一個最合適的數據結構算法來實現查找功能。
下面一起看下常見的查找策略,如下圖:
由于前面說的兩個特點我們首先排除靜態查找的算法。
至于查找樹,我們有二叉樹和多叉樹兩種選擇:
「二叉樹」:如果先查二叉樹的話,由于我們的數據量龐大,二叉樹的深度會變得非常大,我們的索引樹會變成參天大樹,每次查詢會導致很多磁盤IO。
「多叉樹」:多叉樹解決了了樹的深度大的問題,那么我們到底選擇B樹還是B+樹呢?
?B樹 摘自維基百科 https://zh.wikipedia.org/wiki/B%2B樹
??B+樹 摘自維基百科 https://zh.wikipedia.org/wiki/B%2B樹
?從上面圖可知「B+樹的葉子節點存放了所有的索引值」,并且葉子結點之間以鏈表的形式相互關聯,所以我們只需從最左的鏈表遍歷的話即可查找所有的值,最常見的用途就是范圍查找,而B樹則不滿足這范圍查找,又或者說實現特別復雜,所以Mysql最終選擇了使用B+樹實現這一功能。
1.1 B-Tree 索引(B+樹)
先說明一下,雖然叫在Mysql官方叫做B-Tree索引,但采用的是B+樹數據結構。
B-tree索引能夠加快訪問數據的速度,不需要進行全表掃描,而是從索引樹的根節點層層往下搜索,在根節點存放了索引值和指向下一個節點的指針。
下面看下單列索引的數據怎么組織的。
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?key(`uid`)
);
上面User 表給uid列創建了一個索引,那么往表里插入uid(96~102)的時候存儲引擎是怎么管理索引的呢?看下面的索引樹
「1.在葉子節點存放所有的索引值,非葉子節點值是為了更快定位包含目標值的葉子節點」
「2.葉子節點的值是有序的」
「3.葉子節點之間以鏈表形式關聯」
下面在看一下多列(聯合)索引的數據怎么組織的。
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?key(`uid`,`name`)
);
給User 表創建了聯合索引 key(uid,name) 這種情況下他的索引樹是如下圖所示。
特點跟單列索引一樣,不同之處在于他的排序,「如果第一個字段相同時會按第二個索引字段排序」
「如何通過B-tree快速查找數據?」
對于InnoDb 存儲引擎的B-tree索引,會按以下步驟通過索引找到行數據
- 如果使用了聚簇索引(主鍵),則葉子節點上就包含行數據,可直接返回
- 如果使用了非聚簇索引(普通索引),則在葉子節點存了主鍵,再根據主鍵查詢一次上面 的聚簇索引,最后返回數據
對于MyISAM 存儲引擎的B-tree索引,會按以下步驟通過索引找到行數據
- 在MyISAM 的索引樹的葉子節點上除了索引值之外即沒存儲主鍵,也沒存儲行數據,而是存了指向行數據的指針,根據這個指針在從表文件查詢數據。
1.2 Hash 索引(哈希表)
哈希索引是基于哈希表來實現的,只有精確匹配所有的所有列才能生效。
也就是說假設有個hash索引 key (col1,col2) 那么每次只有 col1和col2兩個字段都用才能夠生效。因為生成hash索引的時候是根據一個hash函數對所有的索引列取hash值來實現的。
如下方圖,有個hash索引key(name)
當我們執行?mysql> select * from User where name='張三';?時怎么利用hash索引快速查找的?
2.常見索引種類(應用層面)
「主鍵索引」
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?primary?key(`uid`)
);
主鍵索引是唯一的,通常以表的ID設置為主鍵索引,一個表只能有一個主鍵索引,這是他跟唯一索引的區別。
「唯一索引」
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?unique?key(`name`)
);
唯一索引主要用于業務上的唯一約束,他跟主鍵索引的區別是,一個表可以有多個唯一索引
「單列索引」
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?key(`name`)
);
以某一個字段為索引
「聯合索引」
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?key(`name`,`uid`)
);
兩個或兩個以上字段聯合組成一個索引。使用時需要注意滿足最左匹配原則!
還有其他不常用的就不介紹了~
3.聚簇索引與非聚簇索引
什么是聚簇索引?聚簇索引指的是他的?「索引和行數據」?在一起存儲。也就是在一顆B+樹的葉子結點上存儲的不僅是他的索引值,還有對應的某一行的數據。待會兒看圖便知。
「聚簇索引不是一種索引,而是一種數據存儲組織方式 !!!」
crreate?table?test(??col1?int?not?null,
??col2?int?not?null,
??PRIMARY?KEY(col1),
??KEY(col2)
);
如上所示,表test 由兩個索引,分別是主鍵 col1 和 普通索引 col2。那么這倆索引跟聚簇非聚簇有啥關系呢?
會生成一個聚簇索引和一個非聚簇索引(二級索引),也就是說會組織兩個索引樹。主鍵索引會生成聚簇索引的樹 以及以col2為索引的非聚簇索引的樹。
「InnoDb 將通過主鍵來實現聚簇索引」?,如果沒有主鍵則會選選一個唯一非空索引來實現。如果沒有唯一非空索引則會隱式生成一個主鍵。
下面看下聚簇索引和非聚簇索引在索引樹上數據是怎么分布的,圖片摘自《高性能Nysql》
「下圖是聚簇索引的數據組織方式。col1為主鍵索引的聚簇索引樹」
「索引列是主鍵 col1」可以看出葉子結點除了存儲索引值 列col1 (3994700)值 之外還存儲了其他列的值,如列col2 (92813),如果還有別的列的話也會存儲,或者換句話說聚簇索引樹 在葉子節點上存儲某個索引值對應的一行數據。
「下圖是非聚簇索引(二級索引)的數據組織方式。」
「索引列是 col2」
與聚簇索引不同的是非聚簇索引在索引樹葉子節點上除了索引值之外只存了主鍵值。而聚簇索引則存了一行數據。
假如有一條sql 語句?select * from test where col2=93;上面這條語句會經歷兩次從索引樹查找過程
1.第一步從非聚簇索引的索引樹上找到包含col2=93的葉子節點,并定位到行的主鍵 3 2.第二步 根據主鍵 3 在從聚簇索引定位包含 主鍵=3的葉子節點并返回全部行數據。
以上說的都是基于InnoDb存儲引擎的,「MyISAM」是不支持聚簇索引的,因為他的數據文件和索引文件是相互獨立存儲的?「MyISAM」存儲引擎的索引樹的葉子節點不會存主鍵值,而存一個指向對應行的地址或者說是指針,然后再從表數據文件里去找,如下面圖所示。
結論:
- 聚簇索引: 通常由主鍵或者非空唯一索引實現的,葉子節點存儲了一整行數據
- 非聚簇索引:又稱二級索引,就是我們常用的普通索引,葉子節點存了索引值和主鍵值,在根據主鍵從聚簇索引查
4.覆蓋索引
「覆蓋索引就是指索引包含了所有需要查詢的字段。」
create?table?User(`name`?varchar(50)?not?null,
`uid`?int(4)?not?null,
`gender`?int(2)?not?null,
?key(`uid`,`name`)
);
假如表 User有三個字段 User (name,uid,gender),且有個聯合索引 key(name,uid)那么 執行如下面這條sql查詢時就用到了 覆蓋索引。
select name,uid from User where name in ('a','b') and uid >= 98 and uid <=100 ;
上面這條sql語句使用了聯合索引 key(name,uid),并且只需查找 name,uid兩個字段,所以使用了覆蓋索引。覆蓋索引有什么好處呢?先看一下下面這個圖上面這個圖就是 聯合索引key(name,uid) 所對應的索引樹,從圖中可以看出,如果我們只需查詢(name,uid)兩個字段的話,從索引樹就能得到我們需要查的數據。不需要找到索引值之后再從表數據文件定位對應的行數據了。
覆蓋索引好處 1.避免了對主鍵索引(聚簇)的二次查詢 2.由于不需要回表查詢(從表數據文件)所以大大提升了Mysql緩存的負載
總之大大提升了讀取數據的性能
5.最佳索引使用策略
最后在講講使用索引過程中的避坑指南
「獨立的列」
獨立的列不是指單列索引,而是指索引列不能是表達式的一部分或者是函數的一部分。
select * FROM test where col1 + 1 =100; // 不能是表達式一部分
select * FROM test where ABS(col1) =100; // 不能是函數一部分
「最左匹配原則」
假如有個聯合索引 key (col1,col2)。那么以下查詢是索引無效的
select * from test where col2 = 3;
select * from test where col1 like '%3';
對于最左匹配原則,大家想一下B+樹的葉子節點的關聯就差不多知道為啥需要最左匹配原則了,因為B+的葉子結點,從左到右以鏈表的形式關聯的,索引我們查詢的時候要么范圍查詢,要么有明確的左邊一個開始的索引值,不能跳過或者不明確如 like '%XYZ'這種查詢。
「索引值不能是null值」
單列索引有null值會導致索引無效 多列索引只要有個列有null值會導致索引無效
「使用聚簇索引和覆蓋索引大大提升讀取性能」
因為聚簇索引和覆蓋索引的索引樹上就有了需要的字段,所以不需要回表文件查詢,所以提升了查詢速度
「使用短索引」如果很長的字符串進行查詢,只需匹配一個前綴長度,這樣能夠節省大量索引空間
推薦閱讀:
從傳統Web框架切換到SpringBoot后的總結
阿里云盤正式上架,附下載鏈接+邀請碼
換工作,關于面試的總結
學會這個!微信支付能提現免費!
為什么SimpleDateFormat不是線程安全的?
↘↘↘
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的mysql 聚簇索引和非聚簇索引_图文并茂,说说MySQL索引的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python彩色螺旋线_解决python
- 下一篇: component是什么接口_阿里高级技