再聊 MySQL 聚簇索引

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用版 2核4GB 50GB
简介: 再聊 MySQL 聚簇索引

为什么是再次理解呢?因为松哥之前写过相关的文章介绍过聚簇索引,但是感觉还不够,因此今天想再来和小伙伴们聊一聊这个话题。

1. 什么是聚簇索引

数据库的索引从不同的角度可以划分成不同的类型,聚簇索引便是其中一种。

聚簇索引英文是 Clustered Index,有时候小伙伴们可能也会看到有人将之称为聚集索引等,与之相对的是非聚簇索引或者二级索引。

聚簇索引并不是一种单独的索引类型,而是一种数据的存储方式。在 MySQL 的 InnoDB 存储引擎中,所谓的聚簇索引实际上就是在同一个 B+Tree 中保存了索引和数据行:此时,数据放在叶子结点中,聚簇聚簇,意思就是说数据行和对应的键值紧凑的存在一起。

假设我有如下数据:

id(主键) username age address gender
1 ab 99 深圳
2 ac 98 广州
3 af 88 北京
4 bc 80 上海
5 bg 85 重庆
6 bw 95 天津
7 bw 99 海口
8 cc 92 武汉
9 ck 90 深圳
10 cx 93 深圳

那么它的聚簇索引大概就是这个样子:

dbffc8766412e9412d17955d43c7e637.png

那么大家可以看到,叶子上既有主键值(索引)又有数据行,节点上则只有主键值(索引)。

小伙伴们想想,MySQL 表中的数据在磁盘中只可能保存一份,不可能保存两份,所以,在一个表中,聚簇索引只可能有一个,不可能有多个。

2. 聚簇索引和主键

有的小伙伴搞不清楚这两者之间的关系,甚至将两者划等号,这是一个巨大的误区。

在有的数据库中,支持开发者自由的选择使用哪一个索引作为聚簇索引,但是 MySQL 中是不支持这个特性的。

在 MySQL 中,如果表本身就有设置主键,那么主键就是聚簇索引;如果表本身没有设置主键,则会选择表中的一个唯一且非空的索引来作为聚簇索引;如果表中连唯一非空的索引都没有,那么就会自动选择表中的隐式主键来作为聚簇索引。关于 MySQL 中表的隐式主键,松哥会在将来的文章中和大家介绍。

不过一般来说,还是建议大家自己来为表设置主键,因为隐式主键是自增的,自增的都会存在一个问题:在自增值上会存在非常高的锁竞争问题,主键的上界会称为热点数据,因为所有的插入操作都要主键自增,又不能重复,所以会发生锁竞争进而导致性能降低。

根据上面的介绍,我们可以总结出 MySQL 中聚簇索引和主键索引的关系如下:

  1. 聚簇索引不一定是主键索引。
  2. 主键索引一定是聚簇索引。

3. 聚簇索引优缺点

先来说优点:

相互关联的数据我们可以将之保存在一起。例如有一个用户订单表,我们可以根据 用户 ID + 订单 ID 来聚集所有数据,用户 ID 可能会重复,订单 ID 则不会重复,这样我们就能够将一个用户相关的订单数据都保存在一起,如果需要查询一个用户的所有订单,就会非常快,只需要少量的磁盘 IO 就可以做到。

不需要回表,因此数据访问速度更快。在聚簇索引中,索引和数据都在同一棵 B+Tree 上,因此从聚簇索引中获取到的数据比从非聚簇索引上获取数据更快(非聚簇索引需要回表)。

对于第一点的案例,如果我们想根据用户 ID 查询到这个用户所有的订单 ID,那么此时都不用去到叶子结点了,因为支节点上就有我们需要的数据,所以直接利用覆盖索引的特性,就可以读取到需要的数据。

这些就是聚簇索引一些常见的优点,我们在日常的表设计中,其实应该充分利用好这些优点。

再来看看缺点:

小伙伴们发现,前面我们说的聚簇索引的优势主要是聚簇索引减少了 IO 次数,从而提高了数据库的性能,但是有的 IO 密集型应用,可能直接上一个足够大的内存,把数据都读取到内存中操作,此时聚簇索引就没有啥优势了。

随机主键会导致页分裂问题,主键顺序插入的话,相对来说效率会高一些,因为在 B+Tree 中只需要不断往后面追加即可;但是主键如果是非顺序插入的话,效率就会低很多,因为可能会涉及到页分裂问题。以上面那张图为例,假设每个节点可以保存三条数据,现在我们要插入一个主键是 4.5 的记录,那么就需要把主键为 5 的值往后移动,进而导致主键为 8 的节点也要往后移动。页分裂会导致数据插入效率降低并且占用更多的存储空间。

非聚簇索引(二级索引)查询的时候需要回表。因为一个索引就是一棵索引树,数据都在聚簇索引上,所以如果使用非聚簇索引进行搜索,非聚簇索引的叶子上存储的是主键值,先找到主键值,然后拿着主键值再来聚簇索引上搜索,这样一共就查询了两棵索引树,这就是回表。

4. 最佳实践

看了上面的介绍,相信小伙伴已经了解了,在使用聚簇索引的时候,主键最好不要使用 UUID 这种随机字符串,使用 UUID 随机字符串至少存在两方面的问题:

插入效率低,因为插入可能会导致页分裂,这个前面已经说过了。

UUID 字符串所占用的存储空间远远大于一个 bigint,如果使用 UUID 来做主键,意味着在二级索引中,一个叶子结点能够存储的主键值就非常有限,进而可能会导致树增高,搜索时候 IO 次数增多,性能下降。

所以相对来说,主键自增会优于 UUID。那么主键自增就是最完美的方案了吗?很多小伙伴可能也听说过一句话:没有银弹!所以,主键自增其实也有问题,具体什么问题,我们下便文章继续。



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2天前
|
SQL 关系型数据库 MySQL
MySQL性能优化实战:从索引策略到查询优化
MySQL性能优化聚焦索引策略和查询优化。创建索引如`CREATE INDEX idx_user_id ON users(user_id)`可加速检索;复合索引考虑字段顺序,如`idx_name ON users(last_name, first_name)`。使用`EXPLAIN`分析查询效率,避免全表扫描和大量`OFFSET`。通过子查询优化分页,如LIMIT配合内部排序。定期审查和调整策略以提升响应速度和降低资源消耗。【6月更文挑战第22天】
88 2
|
2天前
|
关系型数据库 MySQL 数据库
MySQL企业级开发重点之事物和索引
MySQL企业级开发重点之事物和索引
8 2
|
5天前
|
存储 SQL 关系型数据库
初识mysql索引 - 小白篇
初识mysql索引 - 小白篇
|
11天前
|
监控 关系型数据库 MySQL
MySQL索引的创建步骤是什么?
【6月更文挑战第15天】MySQL索引的创建步骤是什么?
16 5
|
8天前
|
SQL 存储 关系型数据库
MySQL数据库进阶第二篇(索引,SQL性能分析,使用规则)
MySQL数据库进阶第二篇(索引,SQL性能分析,使用规则)
|
10天前
|
关系型数据库 MySQL 数据库
mysql索引优化
【6月更文挑战第16天】mysql索引优化
15 2
|
11天前
|
存储 关系型数据库 MySQL
MySQL索引的限制
【6月更文挑战第15天】MySQL索引的限制
10 3
|
11天前
|
存储 关系型数据库 MySQL
MySQL索引
【6月更文挑战第15天】MySQL索引
13 3
|
9天前
|
存储 关系型数据库 MySQL
MySQL索引18连问,谁能顶住
MySQL索引18问概览: 1. 索引是提升查询速度的数据结构,如书的目录。 2. 索引类型包括B+tree、Hash、Full-text、R-Tree等,B+tree擅长范围查询,Hash擅长等值比较。 3. 主键索引唯一且不可为空,每表只能一个;唯一索引允许唯一值,可为空。 4. 聚簇索引数据与索引顺序一致,非聚簇索引存储指针。
186 0
MySQL索引18连问,谁能顶住
|
13天前
|
SQL 关系型数据库 MySQL
【MySQL技术内幕】5.6-B+树索引的使用
【MySQL技术内幕】5.6-B+树索引的使用
21 4