Mysql几种索引类型的区别及适用情况

本文介绍了MySQL中的四种主要索引类型:FULLTEXT、HASH、BTREE和RTREE的特点及使用场景。详细探讨了每种索引的工作原理、优势与限制,并提供了实际应用建议。

如大家所知道的,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索引的区别

(1)Hash 索引仅仅能满足"=","IN"和"<=>"查询,不能使用范围查询。
由于 Hash 索引比较的是进行 Hash 运算之后的 Hash 值,所以它只能用于等值的过滤,不能用于基于范围的过滤,因为经过相应的 Hash 算法处理之后的 Hash 值的大小关系,并不能保证和Hash运算前完全一样。
(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使用经历的同学,到时可以交流下!


<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<think> 我们正在回答用户关于MySQL索引类型的问题。根据引用内容,我们可以将MySQL索引类型分为按存储结构分类和按功能分类两种维度。 注意:用户之前的问题是关于VARCHAR和TEXT存储机制的区别,但当前新问题是询问索引类型,因此我们需要专注于索引类型的回答。 根据引用[1]和引用[3]提供的信息: 1. 按存储结构分类:聚簇索引和非聚簇索引(也称为二级索引) 2. 按功能分类:普通索引、唯一索引、主键索引、全文索引、组合索引(联合索引)等。 我们需要详细说明这些索引类型,并注意引用标记。 此外,根据引用[2],全文索引是为文本搜索设计的,适用于VARCHAR、CHAR或TEXT类型列。 因此,我们将索引类型整理如下: 一、按存储结构分类 1. 聚簇索引(Clustered Index) - 特点:数据与索引存储在一起,叶子节点就是数据行。InnoDB中主键索引就是聚簇索引。每张表只能有一个聚簇索引。 - 适用场景:主键查询、范围查询(因为数据物理顺序存储)[^1]。 2. 非聚簇索引(Secondary Index / Non-Clustered Index) - 特点:叶子节点存储的是主键值(InnoDB)或数据的物理地址(MyISAM)。查询时需要回表(通过主键值再去聚簇索引中查找行数据)。一个表可以有多个非聚簇索引。 - 适用场景:非主键列的查询[^1]。 二、按功能分类 1. 普通索引(Index) - 最基本的索引,没有任何约束,仅用于加速查询。 2. 唯一索引(Unique Index) - 索引列的值必须唯一,允许有空值。 - 适用场景:防止出现重复的值,如身份证号、邮箱等[^3]。 3. 主键索引(Primary Key Index) - 特殊的唯一索引,不允许有空值。在InnoDB中,主键索引就是聚簇索引。 4. 全文索引(Fulltext Index) - 专门用于全文搜索,仅适用于MyISAM和InnoDB(MySQL5.6+)引擎,且只能用于CHAR、VARCHAR和TEXT列[^2]。 - 适用场景:大文本字段的搜索,如文章内容、评论等。 5. 组合索引(Composite Index / 联合索引) - 在多个列上立的索引索引的顺序很重要,因为MySQL使用最左前缀原则。 - 适用场景:多条件查询,例如WHERE条件中同时使用多个列[^3]。 - 注意:组合索引比多个单列索引更高效(引用[3]提到,多个单列索引效率低于组合索引)。 此外,还有空间索引(用于地理空间数据类型),但用户没有提到,引用中也没有,可以省略。 最后,按照要求生成相关问题。 注意:所有引用标记要自然地添加在引用内容的末尾。 </think> ### MySQL索引类型详解 #### 一、按存储结构分类 1. **聚簇索引(Clustered Index)** - **特点**: - 数据与索引存储融合(叶子节点即数据本身) - 每表仅有一个(默认主键索引) - 物理存储按主键值有序排列 - **适用场景**: - 主键范围查询(如`WHERE id BETWEEN 100 AND 200`) - 需要高效主键检索的场景 - **InnoDB实现**: ```sql CREATE TABLE users ( id INT PRIMARY KEY, -- 自动生成聚簇索引 name VARCHAR(50) ); ``` [^1] 2. **非聚簇索引(二级索引)** - **特点**: - 叶子节点存储主键值(非数据本身) - 查询需回表操作(二次查找) - 单表可多个 - **数据结构示例**: ``` B+树叶子节点: [索引键值 -> 主键值] ↓ 回表查找 ↓ [实际数据行] ``` - **适用场景**: - 非主键字段查询(如`WHERE email='user@example.com'`) - 覆盖索引优化(避免回表)[^1] #### 二、按功能分类 1. **普通索引(INDEX)** - 基础索引类型,无唯一性约束 - 创语法: ```sql CREATE INDEX idx_name ON users(name); ``` 2. **唯一索引(UNIQUE)** - 强制字段值唯一性(允许NULL值) - 创语法: ```sql CREATE UNIQUE INDEX idx_email ON users(email); ``` 3. **主键索引(PRIMARY KEY)** - 特殊的唯一索引 + 聚簇索引 - 不允许NULL值 - 隐式创: ```sql CREATE TABLE orders ( order_id INT AUTO_INCREMENT PRIMARY KEY -- 自动主键索引 ); ``` 4. **全文索引(FULLTEXT)** - **特点**: - 专为文本搜索设计(支持`VARCHAR`/`CHAR`/`TEXT`) - 使用倒排索引结构 - 支持自然语言搜索 - **创示例**: ```sql ALTER TABLE articles ADD FULLTEXT idx_content(content); ``` - **搜索语法**: ```sql SELECT * FROM articles WHERE MATCH(content) AGAINST('database optimization'); ``` [^2] 5. **组合索引(联合索引)** - **特点**: - 多列组合的单一索引(列顺序敏感) - 遵循最左前缀原则 - **创示例**: ```sql CREATE INDEX idx_city_age ON users(city, age); ``` - **生效场景**: ```sql -- ✅ 生效:使用索引左前缀 SELECT * FROM users WHERE city='Beijing' AND age>25; -- ❌ 失效:跳过左前缀 SELECT * FROM users WHERE age>30; ``` - **性能优势**: - 比多个单列索引更高效(减少索引合并操作) - 支持索引覆盖扫描[^3] --- ### 索引类型对比矩阵 | **索引类型** | **唯一性** | **NULL值** | **存储关联** | **适用场景** | |--------------|------------|------------|--------------------|----------------------------| | 主键索引 | ✅ | ❌ | 聚簇索引 | 主键查询 | | 唯一索引 | ✅ | ✅ | 非聚簇索引 | 业务唯一值(邮箱/手机号) | | 普通索引 | ❌ | ✅ | 非聚簇索引 | 高频查询字段 | | 全文索引 | ❌ | ✅ | 独立倒排索引 | 大文本搜索 | | 组合索引 | ❌ | ✅ | 非聚簇索引 | 多条件联合查询 | --- ### 相关问题延伸 1. **为什么组合索引需要遵循最左前缀原则?其底层实现逻辑是什么?** 2. **全文索引与`LIKE '%keyword%'`查询在性能和结果准确性上有何本质区别?** 3. **如何优化使用非聚簇索引时的回表查询性能?** 4. **在何种场景下应该优先选择哈希索引而非B+树索引?** 5. **MySQL 8.0的倒排索引优化对全文搜索性能带来哪些提升?** [^1]: 聚簇索引与非聚簇索引的存储特性对比 [^2]: 全文索引的文本搜索适用场景 [^3]: 组合索引相比单列索引的效率优势
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值