mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略
索引是幫助mysql獲取數據的數據結構。最常見的索引是Btree索引和Hash索引。
不同的引擎對于索引有不同的支持:Innodb和MyISAM默認的索引是Btree索引;而Mermory默認的索引是Hash索引。
我們在mysql中常用兩種索引算法BTree和Hash,兩種算法檢索方式不一樣,對查詢的作用也不一樣。
一、BTree
BTree索引是最常用的mysql數據庫索引算法,因為它不僅可以被用在=,>,>=,
select * from user where name like ‘jack%’;
select * from user where name like ‘jac%k%’;
如果一通配符開頭,或者沒有使用常量,則不會使用索引,例如:
select * from user where name like ‘%jack’;
select * from user where name like simply_name;
二、Hash
Hash索引只能用于對等比較,例如=,<=>(相當于=)操作符。由于是一次定位數據,不像BTree索引需要從根節點到枝節點,最后才能訪問到頁節點這樣多次IO訪問,所以檢索效率遠高于BTree索引。
但為什么我們使用BTree比使用Hash多呢?主要Hash本身由于其特殊性,也帶來了很多限制和弊端:
1. Hash索引僅僅能滿足“=”,“IN”,“<=>”查詢,不能使用范圍查詢。
2. 聯合索引中,Hash索引不能利用部分索引鍵查詢。
對于聯合索引中的多個列,Hash是要么全部使用,要么全部不使用,并不支持BTree支持的聯合索引的最優前綴,也就是聯合索引的前面一個或幾個索引鍵進行查詢時,Hash索引無法被利用。
3. Hash索引無法避免數據的排序操作
由于Hash索引中存放的是經過Hash計算之后的Hash值,而且Hash值的大小關系并不一定和Hash運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算。
4. Hash索引任何時候都不能避免表掃描
Hash索引是將索引鍵通過Hash運算之后,將Hash運算結果的Hash值和所對應的行指針信息存放于一個Hash表中,由于不同索引鍵存在相同Hash值,所以即使滿足某個Hash鍵值的數據的記錄條數,也無法從Hash索引中直接完成查詢,還是要通過訪問表中的實際數據進行比較,并得到相應的結果。
5. Hash索引遇到大量Hash值相等的情況后性能并不一定會比BTree高
對于選擇性比較低的索引鍵,如果創建Hash索引,那么將會存在大量記錄指針信息存于同一個Hash值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表數據訪問,而造成整體性能底下。
Hash索引
所謂Hash索引,當我們要給某張表某列增加索引時,將這張表的這一列進行哈希算法計算,得到哈希值,排序在哈希數組上。所以Hash索引可以一次定位,其效率很高,而Btree索引需要經過多次的磁盤IO,但是innodb和myisam之所以沒有采用它,是因為它存在著好多缺點:
1、因為Hash索引比較的是經過Hash計算的值,所以只能進行等式比較,不能用于范圍查詢
1、每次都要全表掃描
2、由于哈希值是按照順序排列的,但是哈希值映射的真正數據在哈希表中就不一定按照順序排列,所以無法利用Hash索引來加速任何排序操作
3、不能用部分索引鍵來搜索,因為組合索引在計算哈希值的時候是一起計算的。
4、當哈希值大量重復且數據量非常大時,其檢索效率并沒有Btree索引高的。
Btree索引
至于Btree索引,它是以B+樹為存儲結構實現的。
但是Btree索引的存儲結構在Innodb和MyISAM中有很大區別。
在MyISAM中,我們如果要對某張表的某列建立Btree索引的話,如圖:
所以我們經常會說MyISAM中數據文件和索引文件是分開的。
因此MyISAM的索引方式也稱為非聚集,Innodb的索引方式成為聚集索引。
至于輔助索引,類似于主索引,唯一區別就是主索引上的值不能重復,而輔助索引可以重復。
因此當我們根據Btree索引去搜索的時候,若key存在,在data域找到其地址,然后根據地址去表中查找數據記錄。
至于Innodb它跟上面又有很大不同,它的葉子節點存儲的并不是表的地址,而是數據
我們可以看到這里并沒有將地址放入葉子節點,而是直接放入了對應的數據,這也就是我們平常說到的,Innodb的索引文件就是數據文件,
那么對于Innodb的輔助索引結構跟主索引也相差很多,如圖:
我們可以發現,這里葉子節點存儲的是主鍵的信息,所以我們在利用輔助索引的時候,檢索到主鍵信息,然后再通過主鍵去主索引中定位表中的數據,這就可以說明Innodb中主鍵之所以不宜用過長的字段,由于所有的輔助索引都包含主索引,所以很容易讓輔助索引變得龐大。
我們還可以發現:在Innodb中盡量使用自增的主鍵,這樣每次增加數據時只需要在后面添加即可,非單調的主鍵在插入時會需要維持B+tree特性而進行分裂調整,十分低效。
Btree索引中的最左匹配原則:
Btree是按照從左到右的順序來建立搜索樹的。比如索引是(name,age,sex),會先檢查name字段,如果name字段相同再去檢查后兩個字段。
所以當傳進來的是后兩個字段的數據(age,sex),因為建立搜索樹的時候是按照第一個字段建立的,所以必須根據name字段才能知道下一個字段去哪里查詢。
所以傳進來的是(name,sex)時,首先會根據name指定搜索方向,但是第二個字段缺失,所以將name字段正確的都找到后,然后才會去匹配sex的數據。
建立索引的規則:
1、利用最左前綴:Mysql會一直向右查找直到遇到范圍操作(>,3 and d=6;此時如果建立了(a,b,c,d)索引,那么后面的d索引是完全沒有用到,當換成了(a,b,d,c)就可以用到。
2、不能過度索引:在修改表內容的時候,索引必須更新或者重構,所以索引過多時,會消耗更多的時間。
3、盡量擴展索引而不要新建索引
4、最適合的索引的列是出現在where子句中的列或連接子句中指定的列。
5、不同值較少的列不必要建立索引(性別)。
BTree索引
使用B+樹存儲數據
B+樹索引能夠加快數據的查詢的速度
更加適合進行范圍查找
什么情況下用到BTree索引?
全值匹配的查詢
匹配最左前綴的查詢
匹配列前綴查詢
范圍查找
精確匹配左前列并范圍匹配另外一列
只訪問索引的查詢
BTree索引的限制
如果不是按照索引最左列開始查找,那么無法使用索引。
使用索引時不能跳過索引中的列。
not in、<>、!=操作無法使用索引。
如果查詢中有某個列的范圍查詢,則其右邊的所有列都無法使用索引。
Hash索引
Hash索引是基于Hash表實現的,只有查詢條件精確匹配Hash索引中的列時才能夠使用Hash索引。
對于Hash索引中的所有列,存儲引擎都會為每一行計算一個Hash碼,Hash索引中存儲的就是Hash碼。
Hash索引的限制
Hash索引中包含的只是Hash碼與行指針,因此必須進行二次查找。
Hash索引的建立是由Hash碼構成的,因此Hash索引無法用于排序。
Hash索引不支持部分索引查找也不適合范圍查找。
Hash索引中Hash碼的計算可能存在Hash沖突。
為什么使用索引
索引可以減少存儲引擎需要掃描的數據量。
索引可以幫助我們進行排序以避免臨時表。
索引可以把隨機IO變為順序IO。
索引的性能成本
由于在寫入數據時也要維護索引,因此索引會增加寫操作的成本。
太多的索引會導致查詢優化器的時間,因為查詢優化器要在很多索引中選擇出最合適的索引。
索引優化策略
索引列上不能使用表達式或者是函數。
對于InnoDB來說,索引列大小限制767Byte,對于MyISAM來說是1000Byte。
前綴索引或索引列的選擇性,索引的選擇性是不重復的索引值和表的記錄數的比值。
建立聯合索引如何選擇索引列的順序?
經常會被使用到的列優先。
選擇性高的列優先。
寬度小的列優先使用。
覆蓋索引,包含需要查詢的所有行的值
可以優化緩存,減少磁盤IO
可以減少隨機IO,變成順序IO
可以避免對InnoDB主鍵索引的二次查詢
可以減少MyISAM表進行系統調用
無法使用覆蓋索引的情況
存儲引擎不支持覆蓋索引
查詢中使用了太多的列
使用了雙%號的like查詢
使用索引掃描來優化排序
索引的列順序和order by子句的順序完全一致。
索引紅所有列的升序降序和order by子句完全一致。
order by中字段全部在關聯表中的第一張表中。
使用BTree索引模擬Hash索引優化查詢
只能處理鍵值的全值匹配查找。
所使用的Hash函數決定著索引鍵的大小。
利用索引優化鎖
索引可以減少鎖定的行數。
索引可以加快處理速度,同時也加快了鎖的釋放。
刪除重復和冗余的索引
primary key(id), unique key(id), index(id)
index(a), index(a,b)
primary key(id), index(a,id)
使用工具pt-duplicate-key-checker h=127.0.0.1來檢查
更新索引統計信息及減少索引碎片
analyze table 表名,InnoDB存儲引擎執行該命令不會鎖表只是粗略估算值。
optimize table 表名,使用不當會導致鎖表。
Mysql索引類型Btree和Hash的區別以及使用場景
一點PHP博客分享關于mysql中索引類型的區別特性,遇到單表數據量大的時候很多開發者都會想到給相對的字段建立索引來提高性能(mysql索引的使用),但很少會去關注索引的類型該如何選擇,在mysql中支持有兩種類型,最常用的也是默認的Btree類型,其次就是最容易被忽略的Hash類型。下面將分別介紹兩種索引類型的區別。
Btree類型的索引,Btree又稱b+樹
(1)所有關鍵字都出現在葉子結點的鏈表中(稠密索引),且鏈表中的關鍵字恰好是有序的;(只有根節點存儲關鍵字最后樹的末梢才有值)
(2)非葉子結點相當于是葉子結點的索引(稀疏索引),葉子結點相當于是存儲(關鍵字)數據的數據層。(非根節點,存儲的其實是指向根節點的索引)
(3)不可能在非葉子結點存數據。
(4)根節點橫向也有鏈指針(方便快速順藤摸瓜嘛,沒這個指針,就算下一個取的值是挨著的鄰居,也得跑個圈才能拿到)
通過上述分析,所以能直觀的理解出Btree類型在我們查詢數據時適合用于范圍查找,在某一葉子的節點到另一節點的范圍。例如,orderby等場景都可使用。
Hash索引,其檢索效率非常高的一種精確定位索引。
Hash索引不像B-Tree 索引需要從根節點到枝節點,最后才能訪問到頁節點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高于 B-Tree 索引,它會將計算出的Hash值和對對應的行指針信息記錄在Hash表中。但是雖然Hash效率很高但是同樣也有很多的弊端存在和限制存在。
(1)Hash 索引僅僅能滿足"=","IN"和"<=>"查詢,不能使用范圍查詢。
(2)Hash 索引無法被用來避免數據的排序操作。
(3)Hash 索引不能利用部分索引鍵(組合索引)查詢。
(4)Hash 索引在任何時候都不能避免表掃描。
(5)Hash 索引遇到大量Hash值相等的情況后性能并不一定就會比B-Tree索引高。
因為Hash 索引比較的是進行 Hash 運算之后的 Hash 值,所以它只能用于等值的過濾,不能用于基于范圍的過濾。經過相應的 Hash 算法處理之后的 Hash 值的大小關系,并不能保證和Hash運算前完全一樣,數據庫自然也無法利用索引的數據來避免任何排序運算。
Hash 索引在計算 Hash 值的時候是組合索引鍵合并后再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。
注:關于選擇索引類型的使用,只能說根據不同的條件場景去選擇吧。最后要提醒大家并不是所有數據庫引擎都支持hash索引。
總結
以上是生活随笔為你收集整理的mysql btree检索策略_MySQL之Btree索引和HASH索引的区别以及索引优化策略的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 6大主流开源SQL引擎总结,遥遥领先的是
- 下一篇: 【JAVA】StringTokenize