「笔耕不辍」mysql的索引分类B+和hash详解
MySQL目前主要有以下幾種索引類型:FULLTEXT,HASH,BTREE,RTREE。
那么,這幾種索引有什么功能和性能上的不同呢?
FULLTEXT
即為全文索引,目前只有MyISAM引擎支持。其可以在CREATE TABLE ,ALTER TABLE ,CREATE INDEX 使用,不過目前只有 CHAR、VARCHAR ,TEXT 列上可以創建全文索引。
值得一提的是,在數據量較大時候,現將數據放入一個沒有全局索引的表中,然后再用CREATE INDEX創建FULLTEXT索引,要比先為一張表建立FULLTEXT然后再將數據寫入的速度快很多。
全文索引并不是和MyISAM一起誕生的,它的出現是為了解決WHERE name LIKE “%word%"這類針對文本的模糊查詢效率較低的問題。在沒有全文索引之前,這樣一個查詢語句是要進行遍歷數據表操作的,
可見,在數據量較大時是極其的耗時的,如果沒有異步IO處理,進程將被挾持,很浪費時間,當然這里不對異步IO作進一步講解,想了解的童鞋,自行谷哥。
全文索引的使用方法并不復雜:
創建ALTER TABLE table ADD INDEX FULLINDEX USING FULLTEXT(cname1[,cname2…]);
使用SELECT * FROM table WHERE MATCH(cname1[,cname2…]) AGAINST (‘word’ MODE );
其中, MODE為搜尋方式(IN BOOLEAN MODE ,IN NATURAL LANGUAGE MODE ,IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION / WITH QUERY EXPANSION)。
關于這三種搜尋方式,在這里也不多做交代,簡單地說,就是,布爾模式,允許word里含一些特殊字符用于標記一些具體的要求,如+表示一定要有,-表示一定沒有,*表示通用匹配符,是不是想起了正則,類似吧;
自然語言模式,就是簡單的單詞匹配;含表達式的自然語言模式,就是先用自然語言模式處理,對返回的結果,再進行表達式匹配。
對搜索引擎稍微有點了解的同學,肯定知道分詞這個概念,FULLTEXT索引也是按照分詞原理建立索引的。西文中,大部分為字母文字,分詞可以很方便的按照空格進行分割。
但很明顯,中文不能按照這種方式進行分詞。那又怎么辦呢?這個向大家介紹一個mysql的中文分詞插件Mysqlcft,有了它,就可以對中文進行分詞,想了解的同學請移步Mysqlcft,當然還有其他的分詞插件可以使用。
HASH
Hash這個詞,可以說,自打我們開始碼的那一天起,就開始不停地見到和使用到了。其實,hash就是一種(key=>value)形式的鍵值對,如數學中的函數映射,允許多個key對應相同的value,但不允許一個key對應多個value。
正是由于這個特性,hash很適合做索引,為某一列或幾列建立hash索引,就會利用這一列或幾列的值通過一定的算法計算出一個hash值,對應一行或幾行數據(這里在概念上和函數映射有區別,不要混淆)。
在Java語言中,每個類都有自己的hashcode()方法,沒有顯示定義的都繼承自object類,該方法使得每一個對象都是唯一的,在進行對象間equal比較,和序列化傳輸中起到了很重要的作用。
hash的生成方法有很多種,足可以保證hash碼的唯一性,例如在MongoDB中,每一個document都有系統為其生成的唯一的objectID(包含時間戳,主機散列值,進程PID,和自增ID)也是一種hash的表現。
由于hash索引可以一次定位,不需要像樹形索引那樣逐層查找,因此具有極高的效率。那為什么還需要其他的樹形索引呢?
在這里就不自己總結了。引用下園子里其他大神的文章:來自 14的路 的MySQL的btree索引和hash索引的區別
由于 Hash 索引比較的是進行 Hash 運算之后的 Hash 值,所以它只能用于等值的過濾,不能用于基于范圍的過濾,因為經過相應的 Hash 算法處理之后的 Hash 值的大小關系,并不能保證和Hash運算前完全一樣。
由于 Hash 索引中存放的是經過 Hash 計算之后的 Hash 值,而且Hash值的大小關系并不一定和 Hash 運算前的鍵值完全一樣,所以數據庫無法利用索引的數據來避免任何排序運算;
對于組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合并后再一起計算 Hash 值,而不是單獨計算 Hash 值,所以通過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也無法被利用。
前面已經知道,Hash 索引是將索引鍵通過 Hash 運算之后,將 Hash運算結果的 Hash 值和所對應的行指針信息存放于一個 Hash 表中,由于不同索引鍵存在相同 Hash 值,所以即使取滿足某個 Hash 鍵值的數據的記錄條數,
也無法從 Hash 索引中直接完成查詢,還是要通過訪問表中的實際數據進行相應的比較,并得到相應的結果。
對于選擇性比較低的索引鍵,如果創建 Hash 索引,那么將會存在大量記錄指針信息存于同一個 Hash 值相關聯。這樣要定位某一條記錄時就會非常麻煩,會浪費多次表數據的訪問,而造成整體性能低下。
我稍作補充,講一下HASH索引的過程,順便解釋下上面的第4,5條:
當我們為某一列或某幾列建立hash索引時(目前就只有MEMORY引擎顯式地支持這種索引),會在硬盤上生成類似如下的文件:
hash值 存儲地址
1db54bc745a1 77#45b5
4bca452157d4 76#4556,77#45cc…
…
hash值即為通過特定算法由指定列數據計算出來,磁盤地址即為所在數據行存儲在硬盤上的地址(也有可能是其他存儲地址,其實MEMORY會將hash表導入內存)。
這樣,當我們進行WHERE age = 18 時,會將18通過相同的算法計算出一個hash值==>在hash表中找到對應的儲存地址==>根據存儲地址取得數據。
所以,每次查詢時都要遍歷hash表,直到找到對應的hash值,如(4),數據量大了之后,hash表也會變得龐大起來,性能下降,遍歷耗時增加,如(5)。
BTREE
BTREE索引就是一種將索引值按一定的算法,存入一個樹形的數據結構中,相信學過數據結構的童鞋都對當初學習二叉樹這種數據結構的經歷記憶猶新,反正我當時為了軟考可是被這玩意兒好好地折騰了一番,不過那次考試好像沒怎么考這個。
如二叉樹一樣,每次查詢都是從樹的入口root開始,依次遍歷node,獲取leaf。
BTREE在MyISAM里的形式和Innodb稍有不同
在 Innodb里,有兩種形態:一是primary key形態,其leaf node里存放的是數據,而且不僅存放了索引鍵的數據,還存放了其他字段的數據。二是secondary index,其leaf node和普通的BTREE差不多,只是還存放了指向主鍵的信息.
而在MyISAM里,主鍵和其他的并沒有太大區別。不過和Innodb不太一樣的地方是在MyISAM里,leaf node里存放的不是主鍵的信息,而是指向數據文件里的對應數據行的信息.
RTREE
RTREE在mysql很少使用,僅支持geometry數據類型,支持該類型的存儲引擎只有MyISAM、BDb、InnoDb、NDb、Archive幾種。
相對于BTREE,RTREE的優勢在于范圍查找.
各種索引的使用情況
對于BTREE這種Mysql默認的索引類型,具有普遍的適用性
由于FULLTEXT對中文支持不是很好,在沒有插件的情況下,最好不要使用。其實,一些小的博客應用,只需要在數據采集時,為其建立關鍵字列表,通過關鍵字索引,也是一個不錯的方法,至少我是經常這么做的。
對于一些搜索引擎級別的應用來說,FULLTEXT同樣不是一個好的處理方法,Mysql的全文索引建立的文件還是比較大的,而且效率不是很高,即便是使用了中文分詞插件,對中文分詞支持也只是一般。真要碰到這種問題,Apache的Lucene或許是你的選擇。
正是因為hash表在處理較小數據量時具有無可比擬的素的優勢,所以hash索引很適合做緩存(內存數據庫)。如mysql數據庫的內存版本Memsql,使用量很廣泛的緩存工具Mencached,NoSql數據庫Redis等,都使用了hash索引這種形式。
總結
以上是生活随笔為你收集整理的「笔耕不辍」mysql的索引分类B+和hash详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ubuntu搭建socks5服务
- 下一篇: 12.2版本数据库ORA-20001: