Mysql⼏种索引类型的区别及适⽤情况
如⼤家所知道的,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,有了它,就可以对中⽂进⾏分词,想了解的同学请移步,当然还有其他的分词插件可以使⽤。
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的路的
(1)Hash 索引仅仅能满⾜"=","IN"和"<=>"查询,不能使⽤范围查询。
由于 Hash 索引⽐较的是进⾏ Hash 运算之后的 Hash 值,所以它只能⽤于等值的过滤,不能⽤于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的⼤⼩关系,并不能保证和Hash运算前完全⼀样。
查看mysql索引(2)Hash 索引⽆法被⽤来避免数据的排序操作。
由于 Hash 索引中存放的是经过 Hash 计算之后的 Hash 值,⽽且Hash值的⼤⼩关系并不⼀定和 Hash 运算前的键值完全⼀样,所以数据库⽆法利⽤索引的数据来避免任何排序运算;
(3)Hash 索引不能利⽤部分索引键查询。
对于组合索引,Hash 索引在计算 Hash 值的时候是组合索引键合并后再⼀起计算 Hash 值,⽽不是单独计算 Hash 值,所以通过组合索引的前⾯⼀个或⼏个索引键进⾏查询的时候,Hash 索引也⽆法被利⽤。
(4)Hash 索引在任何时候都不能避免表扫描。
前⾯已经知道,Hash 索引是将索引键通过 Hash 运算之后,将 Hash运算结果的 Hash 值和所对应的⾏指针信息存放于⼀个 Hash 表中,由于不同索引键存在相同 Hash 值,所以即使取满⾜某个 Hash 键值的数据的记录条数,也⽆法从 Hash 索引中直接完成查询,还是要通过访问表中的实际数据进⾏相应的⽐较,并得到相应的结果。
(5)Hash 索引遇到⼤量Hash值相等的情况后性能并不⼀定就会⽐B-Tree索引⾼。
对于选择性⽐较低的索引键,如果创建 Hash 索引,那么将会存在⼤量记录指针信息存于同⼀个 Hash 值相关联。这样要定位某⼀条记录时就会⾮常⿇烦,会浪费多次表数据的访问,⽽造成整体性能低下。
愚安我稍作补充,讲⼀下HASH索引的过程,顺便解释下上⾯的第4,5条:
当我们为某⼀列或某⼏列建⽴hash索引时(⽬前就只有MEMORY引擎显式地⽀持这种索引),会在硬盘上⽣成类似如下的⽂件:
hash值存储地址
1db54bc745a177#45b5
4bca452157d476#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的优势在于范围查.
各种索引的使⽤情况
(1)对于BTREE这种Mysql默认的索引类型,具有普遍的适⽤性
(2)由于FULLTEXT对中⽂⽀持不是很好,在没有插件的情况下,最好不要使⽤。其实,⼀些⼩的博客应⽤,只需要在数据采集时,为其建⽴关键字列表,通过关键字索引,也是⼀个不错的⽅法,⾄少愚安我是经常这么做的。
(3)对于⼀些搜索引擎级别的应⽤来说,FULLTEXT同样不是⼀个好的处理⽅法,Mysql的全⽂索引建⽴的⽂件还是⽐较⼤的,⽽且效率不是很⾼,即便是使⽤了中⽂分词插件,对中⽂分词⽀持也只是⼀般。真要碰到这种问题,Apache的Lucene或许是你的选择。
(4)正是因为hash表在处理较⼩数据量时具有⽆可⽐拟的素的优势,所以hash索引很适合做缓存(内存数据库)。如mysql数据库的内存版本Memsql,使⽤量很⼴泛的缓存⼯具Mencached,NoSql数据库redis等,都使⽤了hash索引这种形式。当然,不想学习这些东西的话Mysql的MEMORY引擎也是可以满⾜这种需求的。
(5)⾄于RTREE,愚安我⾄今还没有使⽤过,它具体怎么样,我就不知道了。有RTREE使⽤经历的同
学,到时可以交流下!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论