MySQL 索引类型
Posted Wallace JW
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL 索引类型相关的知识,希望对你有一定的参考价值。
前言
在 SQL 优化中,索引是至关重要的一环,能给查询效率带来质的飞跃,但是索引并不是万能的,不合理的索引设计甚至会拖慢查询效率。本文将详细介绍索引的概览和分类,并讨论使用索引时应该权衡的要素。
文章目录
概览
索引定义
索引是一种专门用于帮助 SQL 高效获取数据的数据结构,一个常用的例子是,索引类似于一本书的目录,可以快速对特定值就行定位和查找,从而大大加快数据查询的效率。实际上,索引也是一张表,这张表保存了主键与索引字段,并指向实体表的记录(类似指针)。
索引优缺点
优点
- 索引大大减小了服务器需要扫描的数据量
- 索引可以帮助服务器避免排序和临时表
- 索引可以将随机IO变成顺序IO
- 索引对于InnoDB(对索引支持行级锁)非常重要,InnoDB仅对需要访问的元组加锁,而索引能够减少InnoDB访问的元组数。如果查询不能使用索引,mysql会进行全表扫描,并锁住每一个元组,不管是否真正需要。
缺点
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度。因为更新表时,MySQL不仅要保存数据,还要保存索引文件。因此,对应更新非常频繁的字段,通常不建议使用索引。
- 建立索引会占用磁盘空间。
- 如果某个数据列包含许多重复的内容,为它建立索引效果就很差。除非数据非常不均衡,那么索引查询小类时效率会提高。
- 比如对性别字段建立索引,一百万条数据,如果男女各 50 万,索引效果就很差;
- 如果只有 100 个女性,那么用索引查询女性的时候效率会大大提升,但是查询男性效率就非常差。
- 对于非常小的表,索引意义不大,大部分情况下简单的全表扫描更高效。
因此应该只为最经常查询和最经常排序的数据列建立索引。MySQL里同一个数据表里的索引总数限制为16个。
索引类型
按功能逻辑划分
从功能逻辑来划分,索引主要分为 普通索引、唯一索引、主键索引和全文索引
普通索引
最基本的索引,它没有任何限制。普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列创建索引。
普通索引的创建有三种方式。
# 创建索引
CREATE INDEX idx_username ON user_tbl(username);
# 对于字符串字段,可以手动指定长度,如 user_tbl(username(5)),表示只用前五个字符来做索引,可以进一步加快查询效率,索引长度要小于字段长度
# 修改表结构
ALTER TABLE user_tbl ADD INDEX idx_username (username)
# 创建表的时候直接指定,如
CREATE TABLE user_tbl(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX idx_username (username)
);
删除索引
DROP INDEX idx_username ON user_tbl;
查看索引
SHOW INDEX FROM user_tbl;
唯一索引
它与前面的普通索引类似,不同的就是:普通索引允许被索引的数据列包含重复的值。而唯一索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
唯一索引的创建跟普通索引类似:
#创建索引
CREATE UNIQUE INDEX idx_username ON user_tbl(username);
# 修改表结构
ALTER TABLE user_tbl ADD UNIQUE idx_username (username)
# 创建表的时候直接指定
CREATE TABLE user_tbl(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
UNIQUE idx_username (username)
);
主键索引
它是一种特殊的唯一索引,不允许有空值。一张表只能有一个主键,一般是在建表的时候同时创建。
CREATE TABLE user_tbl(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
PRIMARY KEY(ID)
);
与之类似的是外键索引,如果为某个外键字段定义了一个外键约束条件,MySQL就会定义一个内部索引来帮助自己以最有效率的方式去管理和使用外键约束条件。
全文索引
较少使用,不介绍。
按物理实现划分
按物理实现方式来划分,通常可以分为聚集索引和非聚集索引。
聚集索引(clustered index)
存储内容是按照聚集索引排序的,聚集索引的顺序和行记录的顺序一致,一张表只能有一个聚集索引。聚集索引的叶子节点直接储存聚集索引指向的内容,因此查询的时候只需要进行一次查找。
聚集索引在创建主键时自动生成,如果没有主键,则根据第一个不为空的唯一索引自动生成,如果还没有,则自动生成一个隐式的聚集索引。
需要注意的是,在进行查询操作的时候,聚集索引的效率更高,因为少了一次查找;但是进行修改操作的时候,效率比非聚集索引低,因为直接修改了数据内容,为了标准数据内容的顺序和聚集索引顺序一致,会对数据页重新排序。
非聚集索引(non-clustered index)
非聚集索引虽然索引项是顺序存储的,但是索引项对应的内容是随机存储的,系统会维护单独的索引表来存储索引。
非聚集索引的叶子节点存储的是数据的地址,查询非聚集索引的时候,系统会进行两次查找,先查找索引,再查找索引对应位置的数据。因此非聚集索引也叫二级索引或者辅助索引。
按字段个数划分
按字段个数可以把索引分为单一索引和联合索引。
单一索引
索引字段只有一列时为单一索引,上述所有索引都是单一索引。
组合索引
将多个字段组合在一起创建的索引叫联合索引。如下:
ALTER TABLE user_tbl ADD INDEX idx_name_city_age (username,city,age);
最左匹配原则
建立这样的联合索引,其实是相当于分别建立了下面三组联合索引:
usernname,city,age
usernname,city
usernname
为什么没有 city,age 这样的联合索引呢?这是因为MySQL联合索引的最左匹配原则,只会按照最左优先的顺序进行索引匹配,也就是说,(x,y,z) 和 (z,y,x) 是不同的索引,即使是使用联合索引中的字段查询,联合索引也有可能失效。
对于 (x,y,z),只有在以下查询条件联合索引会生效:
WHERE x = 1
WHERE x = 1 AND y = 1
WHERE x = 1 AND y = 1 AND z = 1
对于其他情况,比如 WHERE y = 1
、 WHERE x = 1 AND z = 1
、WHERE y = 1 AND z = 1
等,就不会匹配联合索引,索引失效。
顺便提一下,可以用 explain
命令来查看在某个查询语句中索引是否生效,具体用法请参考官网文档。
如果分别在 x, y, z 上建立单列索引,让该表有3个单列索引,索引效率也会大不一样,在联合索引生效的情况下,单个索引的效率远远低于联合索引。因为虽然此时有了三个索引,但 MySQL 只能用到其中的那个系统认为似乎是最有效率的单列索引。
以上是关于MySQL 索引类型的主要内容,如果未能解决你的问题,请参考以下文章