MySQL索引类型

MySQL索引类型

一、简介

MySQL 主要索引类型有如下几种:

1、主键索引
2、唯一索引
3、普通索引
4、空间索引
5、全文索引

假设有如下一张表:

CREATE TABLE `t1` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `u1` int unsigned NOT NULL DEFAULT '0',
  `u2` int unsigned NOT NULL DEFAULT '0',
  `u3` varchar(20) NOT NULL DEFAULT '',
  `u4` varchar(35) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB

二、索引类型

2.1、聚簇索引

索引与数据存放在一起,找到索引的同时也找到了数据;聚簇索引具有唯一性,一张表只有一个聚簇索引。
聚簇索引默认是主键,如果表中没有定义主键,InnoDB 会选择一个非空唯一索引代替。如果没有,InnoDB 会定义一个隐藏的_rowid 列来作为聚簇索引。

2.2、非聚簇索引

索引与数据分开存放,索引结构的叶子节点指向了数据的对应行。

2.3、主键索引

# 查看创建的索引关键词
PRIMARY KEY (`id`)

2.4、唯一索引

索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。

# 创建唯一索引
mysql> alter table t1 add unique idx_u1(`u1`);

# 查看创建的索引关键词
UNIQUE KEY `idx_u1` (`u1`)

2.5、单列索引

即索引创建在单个列上。

# 创建单列索引
mysql> alter table t1 add index idx_u1(`u1`);

# 查看创建的索引关键词
KEY `idx_u1` (`u1`)

2.6、多列索引

创建多列索引时记得遵循最左匹配原则,把区分度较高的字段放前面。

# 创建多列索引
mysql> alter table t1 add index idx_u1_u2(`u1`,`u2`);

# 查看创建的多列索引关键词
KEY `idx_u1_u2` (`u1`,`u2`)

2.7、前缀索引

即当字段的长度超过索引限制,可以为字段的部分前缀创建索引。

# 创建前缀索引,取字符串的前4个字符
mysql> alter table t1 add index idx_u3(`u3`(4));

# 查看创建的索引关键词
KEY `idx_u3` (`u3`(4))

2.8、倒序索引

8.0 版本出的新功能,以往创建倒叙索引可以创建成功,但实际上仍然是顺序的。

# 5.7 创建倒序索引
mysql> select u1 from t1 limit 10;
+----+
| u1 |
+----+
| 12 |
| 23 |
| 12 |
| 34 |
+----+
10 rows in set (0.00 sec)
# 创建倒序索引
mysql> alter table t1 add index idx_u3(u3 desc);
# 实际查出来还是顺序
mysql> select u1 from t1 limit 10;
+----+
| u1 |
+----+
| 12 |
| 12 |
| 12 |
| 12 |
+----+

# 8.0 创建倒序索引
mysql> select u1 from t1 limit 5;
+----+
| u1 |
+----+
| 12 |
| 23 |
| 12 |
| 34 |
+----+
5 rows in set (0.00 sec)

# 添加索引
mysql> alter table t1 add index idx_u1(u1 desc);

# 查询倒序索引成功
mysql> select u1 from t1 limit 5;
+----+
| u1 |
+----+
| 74 |
| 74 |
| 74 |
| 74 |
+----+
5 rows in set (0.00 sec)

2.9、函数索引

# 创建函数索引
mysql> alter table t1 add index idx_abs_u2 ((ABS(`u2`)));

# 查看创建的索引关键词
KEY `idx_abs_u2` ((abs(`u2`)))

2.10、表达式索引

# 创建表达式索引
mysql> alter table t1 add index idx_u1u2 ((u1 + u2));

# 查看创建的索引关键词
KEY `idx_u1u2` (((`u1` + `u2`)))

2.11、不可见索引

# 设置不可见(invisible),修改为可见(visible)
mysql> ALTER TABLE t1 ALTER INDEX idx_u1 INVISIBLE;

# 查看不可见索引关键词
KEY `idx_u1` (`u1` DESC) /*!80000 INVISIBLE */

# 解析查询时时全表扫描
mysql> explain select * from t1 order by u1 desc limit 3;
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 50184 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
1 row in set, 1 warning (0.01 sec)

# 执行SQL时即便force index也不可用,提示不存在
mysql> explain select * from t1 force index(idx_u1)  order by u1 desc limit 3;
ERROR 1176 (42000): Key 'idx_u1' doesn't exist in table 't1'

2.12、不可见索引

# 设置不可见(invisible),修改为可见(visible)
mysql> ALTER TABLE t1 ALTER INDEX idx_u1 INVISIBLE;

# 查看不可见索引关键词
KEY `idx_u1` (`u1` DESC) /*!80000 INVISIBLE */

# 解析查询时时全表扫描
mysql> explain select * from t1 order by u1 desc limit 3;
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows  | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 50184 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------+
1 row in set, 1 warning (0.01 sec)

# 执行SQL时即便force index也不可用,提示不存在
mysql> explain select * from t1 force index(idx_u1)  order by u1 desc limit 3;
ERROR 1176 (42000): Key 'idx_u1' doesn't exist in table 't1'

2.13、空间索引

空间索引是对空间数据类型的字段建立的索引,MYSQL使用SPATIAL关键字进行扩展,使其能够在空间数据类型的语法上创建空间索引。

# 建表
CREATE TABLE `gis_position` (
  `id` int NOT NULL,
  `gis` geometry NOT NULL COMMENT '空间位置信息',
  `geohash` varchar(20) GENERATED ALWAYS AS (st_geohash(`gis`,12)) VIRTUAL,
  primary key(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='空间位置信息';

# 创建空间索引
mysql> alter table gis_position add SPATIAL KEY `idx_gis` (`gis`) ;

# 查看索引关键信息
SPATIAL KEY `idx_gis` (`gis`)

2.14、全文索引

# 创建全文索引
mysql> alter table t1 add fulltext index idx_fulltext_u4(`u4`) with parser ngram;

# 查看索引关键信息
FULLTEXT KEY `idx_fulltext_u4` (`u4`) /*!50100 WITH PARSER `ngram` */

三、索引创建注意点

3.1、最左前缀原则

高版本Mysql,不遵守最左前缀原则,索引也会生效。
但是我们仍应遵守最左前缀原则,以免版本更迭带来的麻烦。

3.2、选择合适的字段

1、不为NULL的字段

索引字段的数据应该尽量不为NULL,因为对于数据为NULL的字段,数据库较难优化。如果字段频繁被查询,但又避免不了为NULL,建议使用0,1,true,false这样语义较为清晰的短值或短字符作为替代。

2、被频繁查询的字段

创建索引的字段应该是查询操作非常频繁的字段。

3、被作为条件查询的字段

被作为WHERE条件查询的字段,应该被考虑建立索引。

4、被经常频繁用于连接的字段

经常用于连接的字段可能是一些外键列,对于外键列并不一定要建立外键,只是说该列涉及到表与表的关系。对于频繁被连接查询的字段,可以考虑建立索引,提高多表连接查询的效率。

3.2、不合适创建索引的字段

1、被频繁更新的字段应该慎重建立索引

虽然索引能带来查询上的效率,但是维护索引的成本也是不小的。
如果一个字段不被经常查询,反而被经常修改,那么就更不应该在这种字段上建立索引了。

2、不被经常查询的字段没有必要建立索引

3、尽可能的考虑建立联合索引而不是单列索引

因为索引是需要占用磁盘空间的,可以简单理解为每个索引都对应着一颗B+树。如果一个表的字段过多,索引过多,那么当这个表的数据达到一个体量后,索引占用的空间也是很多的,且修改索引时,耗费的时间也是较多的。如果是联合索引,多个字段在一个索引上,那么将会节约很大磁盘空间,且修改数据的操作效率也会提升。

4、注意避免冗余索引

冗余索引指的是索引的功能相同,能够命中 就肯定能命中 ,那么 就是冗余索引如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的 在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。

5、考虑在字符串类型的字段上使用前缀索引代替普通索引

前缀索引仅限于字符串类型,较普通索引会占用更小的空间,所以可以考虑使用前缀索引带替普通索引。

评论

暂无

添加新评论