MySQL索引的创建与设计原则

1. 索引的分类

从功能逻辑上说,索引主要有 4 种,分别是普通索引、唯一索引、主键索引、全文索引。

按照物理实现方式,索引可以分为 2 种:聚簇索引和非聚簇索引。

按照作用字段个数进行划分,分成单列索引和联合索引。

2 创建索引

复制代码
CREATE TABLE table_name [col_name data_type] `
`[UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name [length]) [ASC | DESC]`
`

UNIQUE、FULLTEXT和SPATIAL为可选参数,分别表示唯一索引、全文索引和空间索引;

INDEX与KEY为同义词,两者的作用相同,用来指定创建索引;

index_name指定索引的名称,为可选参数,如果不指定,那么MySQL默认col_name为索引名;

col_name为需要创建索引的字段列,该列必须从数据表中定义的多个列中选择;

length为可选参数,表示索引的长度,只有字符串类型的字段才能指定索引长度;

ASC或DESC指定升序或者降序的索引值存储。

2.1 创建普通索引

复制代码
CREATE TABLE book(` 
`    book_id INT ,` 
`    book_name VARCHAR(100),` 
`    authors VARCHAR(100),` 
`    info VARCHAR(100)` `,` 
`    comment VARCHAR(100),` 
`    year_publication YEAR,` 
    `INDEX(year_publication)` 
`);`
`

2.2 创建唯一索引

复制代码
CREATE TABLE test1(` 
`    id INT NOT NULL,` 
`    name varchar(30) NOT NULL,` 
`    UNIQUE INDEX uk_idx_id(id)` 
`);

2.3 主键索引

复制代码
CREATE TABLE student (` 
`    id INT(10) UNSIGNED AUTO_INCREMENT,` 
`    student_no VARCHAR(200),`
`    student_name VARCHAR(200),` 
`    PRIMARY KEY(id)` 
`);`
`# 删除主键索引`
`ALTER TABLE student drop PRIMARY KEY ;

2.4 创建单列索引

复制代码
CREATE TABLE test2(` 
`    id INT NOT NULL,` 
`    name CHAR(50) NULL,` 
`    INDEX single_idx_name(name(20))` 
`);

2.5 创建组合索引

复制代码
CREATE TABLE test3(` 
`    id INT(11) NOT NULL,` 
`    name CHAR(30) NOT NULL,` 
`    age INT(11) NOT NULL,` 
`    info VARCHAR(255),` 
`    INDEX multi_idx(id,name,age)` 
`);

2.6 创建全文索引

复制代码
CREATE TABLE `papers` (` 
`    id` int(10) unsigned NOT NULL AUTO_INCREMENT,` 
`    `title` varchar(200) DEFAULT NULL,` 
`    `content` text, PRIMARY KEY (`id`),` 
`    FULLTEXT KEY `title` (`title`,`content`)` 
`) ENGINE=MyISAM DEFAULT CHARSET=utf8;`
`SELECT * FROM papers WHERE MATCH(title,content) AGAINST ('查询字符串');

2.7 创建空间索引

复制代码
CREATE TABLE test5(` 
`    geo GEOMETRY NOT NULL,` 
`    SPATIAL INDEX spa_idx_geo(geo)` 
`) ENGINE=MyISAM;`
`

3. 在已经存在的表上创建索引

3.1 使用ALTER TABLE语句创建索引

复制代码
ALTER TABLE table_name `
`ADD [UNIQUE | FULLTEXT | SPATIAL] [INDEX | KEY] [index_name] (col_name[length],...) [ASC | DESC]

3.2 使用CREATE INDEX创建索引

复制代码
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name `
`ON table_name (col_name[length],...) [ASC | DESC]

4. 删除索引

4.1 使用ALTER TABLE删除索引

复制代码
ALTER TABLE table_name DROP INDEX index_name;

4.2 使用DROP INDEX语句删除索引

复制代码
DROP INDEX index_name ON table_name;

5. MySQL8.0索引新特性

5.1 支持降序索引

CREATE TABLE ts1(a int,b int,index idx_a_b(a,b desc));

5.2 隐藏索引

从MySQL 8.x开始支持隐藏索引(invisible indexes),只需要将待删除的索引设置为隐藏索引,使查询优化器不再使用这个索引(即使使用force index(强制使用索引),优化器也不会使用该索引),确认将索引设置为隐藏索引后系统不受任何响应,就可以彻底删除索引。这种通过先将索引设置为隐藏索引,再删除索引的方式就是软删除。

5.2.1 创建表时直接创建

复制代码
CREATE TABLE tablename(` 
`    propname1 type1[CONSTRAINT1],` 
`    propname2 type2[CONSTRAINT2],` 
`    ......`
`    propnamen typen,` 
`    INDEX [indexname](propname1 [(length)]) INVISIBLE `
`);

5.2.2 在已经存在的表上创建

复制代码
CREATE INDEX indexname `
`ON tablename(propname[(length)]) INVISIBLE;

5.2.3 通过ALTER TABLE语句创建

复制代码
ALTER TABLE tablename `
`ADD INDEX indexname (propname [(length)]) INVISIBLE;

5.2.4 切换索引可见状态

复制代码
ALTER TABLE tablename ALTER INDEX index_name INVISIBLE; #切换成隐藏索引 `
`ALTER TABLE tablename ALTER INDEX index_name VISIBLE; #切换成非隐藏索引

6. 索引的设计原则

6.1 哪些情况适合创建索引

  1. 字段的数值有唯一性的限制

索引本身可以起到约束的作用,比如唯一索引、主键索引都可以起到唯一性约束的,因此在我们的数据表中,如果某个字段是唯一的,就可以直接创建唯一性索引,或者主键索引。这样可以更快速地通过该索引来确定某条记录。

业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。(来源:Alibaba)

说明:不要以为唯一索引影响了insert速度,这个速度损耗可以忽略,但提高查找速度是明显的。

  1. 频繁作为 WHERE 查询条件的字段

某个字段在SELECT语句的 WHERE 条件中经常被使用到,那么就需要给这个字段创建索引了。尤其是在数据量大的情况下,创建普通索引就可以大幅提升数据查询的效率。

  1. 经常 GROUP BY 和 ORDER BY 的列

索引就是让数据按照某种顺序进行存储或检索,因此当我们使用 GROUP BY 对数据进行分组查询,或者使用 ORDER BY 对数据进行排序的时候,就需要对分组或者排序的字段进行索引。如果待排序的列有多个,那么可以在这些列上建立组合索引。

  1. UPDATE、DELETE 的 WHERE 条件列

对数据按照某个条件进行查询后再进行 UPDATE 或 DELETE 的操作,如果对 WHERE 字段创建了索引,就能大幅提升效率。原理是因为我们需要先根据 WHERE 条件列检索出来这条记录,然后再对它进行更新或删除。如果进行更新的时候,更新的字段是非索引字段,提升的效率会更明显,这是因为非索引字段更新不需要对索引进行维护。

5.DISTINCT 字段需要创建索引

有时候我们需要对某个字段进行去重,使用 DISTINCT,那么对这个字段创建索引,也会提升查询效率。

  1. 多表 JOIN 连接操作时,创建索引注意事项

首先,连接表的数量尽量不要超过 3 张,因为每增加一张表就相当于增加了一次嵌套的循环,数量级增长会非常快,严重影响查询的效率。

其次,对 WHERE 条件创建索引,因为 WHERE 才是对数据条件的过滤。如果在数据量非常大的情况下,没有 WHERE 条件过滤是非常可怕的。

最后,对用于连接的字段创建索引,并且该字段在多张表中的类型必须一致。

  1. 使用列的类型小的创建索引

我们这里所说的类型大小指的就是该类型表示的数据范围的大小。

数据类型越小,在查询时进行的比较操作越快

数据类型越小,索引占用的存储空间就越少,在一个数据页内就可以放下更多的记录,从而减少磁盘I/O带来的性能损耗,也就意味着可以把更多的数据页缓存在内存中,从而加快读写效率。

这个建议对于表的主键来说更加适用,因为不仅是聚簇索引中会存储主键值,其他所有的二级索引的节点处都会存储一份记录的主键值,如果主键使用更小的数据类型,也就意味着节省更多的存储空间和更高效的I/O。

  1. 使用字符串前缀创建索引

区分度计算公式:

count(distinct left(列名, 索引长度))/count(*)

【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。

说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90% 以上。

  1. 区分度高(散列性高)的列适合作为索引

列的基数指的是某一列中不重复数据的个数,比方说某个列包含值2,5,8,2,5,8,2,5,8,虽然有9条记录,但该列的基数却是3。也就是说,**在记录行数一定的情况下,列的基数越大,该列中的值越分散;列的基数越小,该列中的值越集中。**这个列的基数指标非常重要,直接影响我们是否能有效的利用索引。最好为列的基数大的列建立索引,为基数太小的列建立索引效果可能不好。

可以使用公式select count(distinct a)/count(*) from t1计算区分度,越接近1越好,一般超过33%就算是比较高效的索引了。

拓展:联合索引把区分度高(散列性高)的列放在前面。

  1. 使用最频繁的列放到联合索引的左侧

  2. 在多个字段都要创建索引的情况下,联合索引优于单值索引

6.2 限制索引的数目

在实际工作中,我们也需要注意平衡,索引的数目不是越多越好。我们需要限制每张表上的索引数量,建议单张表索引数量不超过6个。原因:

每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。

索引会影响INSERT、DELETE、UPDATE等语句的性能,因为表中的数据更改的同时,索引也会进行调整和更新,会造成负担。

优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,会增加MySQL优化器生成执行计划时间,降低查询性能。

6.3 哪些情况不适合创建索引

  1. 在where中使用不到的字段,不要设置索引

  2. 数据量小的表最好不要使用索引

  3. 有大量重复数据的列上不要建立索引

  4. 避免对经常更新的表创建过多的索引

  5. 不建议用无序的值作为索引(例如身份证、UUID(在索引比较时需要转为ASCII,并且插入时可能造成页分裂)、MD5、HASH、无序长字符串等。

  6. 删除不再使用或者很少使用的索引

  7. 不要定义冗余或重复的索引

相关推荐
AI 嗯啦1 小时前
SQL详细语法教程(七)核心优化
数据库·人工智能·sql
@蓝眼睛1 小时前
mac的m3芯片安装mysql
mysql·macos
ClouGence2 小时前
三步搞定!GaussDB 实时数据入仓
数据库·后端
冰块的旅行2 小时前
MySQL 的时区问题
mysql
舒一笑3 小时前
如何优雅统计知识库文件个数与子集下不同文件夹文件个数
后端·mysql·程序员
鼠鼠我捏,要死了捏3 小时前
生产环境MongoDB分片策略优化与故障排查实战经验分享
数据库·mongodb·分片
KaiwuDB4 小时前
KWDB 分布式架构探究——数据分布与特性
数据库·分布式
笨蛋不要掉眼泪4 小时前
Spring Boot集成腾讯云人脸识别实现智能小区门禁系统
java·数据库·spring boot
Leiwenti5 小时前
MySQL高阶篇-数据库优化
数据结构·数据库·mysql
你的电影很有趣5 小时前
lesson44:Redis 数据库全解析:从数据类型到高级应用
数据库·redis·缓存