前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MySQL唯一索引和普通索引

MySQL唯一索引和普通索引

作者头像
shysh95
发布2022-02-16 21:30:26
1.7K0
发布2022-02-16 21:30:26
举报
文章被收录于专栏:shysh95
代码语言:javascript
复制
create table t(
    id int primary key,
    name varchar(16),
    k int not null
) engine = InnoDB;

insert into t(id, name, k) values
(1, 'Java', 100),
(2, 'Python', 200),
(3, 'Go', 300),
(5, 'MySQL', 500),
(6, 'Spark', 600)

我们使用上节的SQL进行分析普通索引和唯一索引的区别。

普通索引和唯一索引查询

代码语言:javascript
复制
select * from t where k = 500;

查询语句会在k索引树上的树根开始,按层搜索到叶子节点(点位到右下角的数据页),然后在数据页内部再通过二分法定位记录。

  • 普通索引,查找到(500,5)这条记录后,还需要查找下一个记录,直到碰到第一个不满足k=500条件的记录
  • 唯一索引,由于索引具有唯一性,所以查找到第一个满足条件的记录后就会停止继续检索

唯一索引带来的查询性能提升几乎微乎其微,因为InnoDB的数据是按照数据页为单位进行读取,当我们select一条记录时,不是将该记录从磁盘读出,而是以页(InnoDB中,每个数据页默认是16KB)为单位从磁盘中读入内存。

当找到k=500的记录的时候,他所在的数据页就都在内存中了,他的下一条记录大概率也在该数据页里,对于普通索引来说只是需要做一次寻址和计算,CPU成本几乎可以忽略不计。

什么是change buffer?

当更新一个数据页时,如果数据页在内存中直接更新,如果这个数据页不在内存中,在不影响数据一致性的前提下,InnoDB会将更新操作缓存在change buffer中,这样就不需要从磁盘中读入该数据页。下次查询需要访问该数据页时,将数据页读入内存,然后执行change buffer中与这个页有关的操作。

change buffer是可以持久化的数据,既可以在内存中,也会被写入磁盘。

change buffer中的操作应用到原始数据页并获取最新结果的过程称之为merge。触发merge的操作主要有:

  • 查询访问数据页
  • 后台线程定期merge
  • 数据库正常关闭的过程中也会执行merge

change buffer使用的是buffer pool的内存,因此不能无限增大,change buffer的大小可以通过innodb_change_buffer_max_size来动态设置。比如设置为30,表示change buffer的大小最多只能占用buffer pool的30%。

唯一索引和普通索引的插入

假设我们在表中需要插入一条新的数据(4, 'Flink', 400),InnoDB对于唯一索引和普通索引的处理有些区别:

  1. 假设记录要更新的目标页在内存中,处理流程如下:
  • 如果是唯一索引,找到300和500之间的位置,判断没有冲突,插入该值,语句执行结束
  • 如果是普通索引,找到300和500之间的位置,插入该值,语句执行结束
  1. 假设记录要更新的目标页不在内存中,处理流程如下:
  • 如果是唯一索引,需要将数据页读入内存,判断没有冲突插入该值,语句结束
  • 如果是普通索引,则将更新记录在change buffer,语句执行结束。

数据从磁盘读入内存设计随机IO,极为耗时,change buffer因为可以减少随机磁盘的访问,所以普通索引的更新性能在特定情况下会远远高于唯一索引。

change buffer的使用场景

普通索引会使用到change buffer,一个数据页在merge之前,change buffer记录的变更越多,收益就越大。

对于写多读少的应用系统特别适合change buffer,因为页面在写完以后被访问到的概率特别小,此时change buffer将会最大可能的发挥作用。

但是如果一个应用系统读多写少,即使更新操作记录在了change buffer,但由于后续很有可能接着访问该数据页,将会立即触发merge操作。这样随机IO的次数不会减少,反而增加了change buffer的维护代价。

唯一索引和普通索引

唯一索引和普通索引在查询性能上基本没有差别,但在更新上普通索引会快于唯一索引。所以在可以选择普通索引的前提下尽可能选择普通索引。

change buffer和redo log

代码语言:javascript
复制
insert into t(id, name, k) values
(0, 'Hive', 50)
(4, 'Flink', 400)

假设k=400的数据页Page2不在内存中,k=50的数据页Page1在内存中,change buffer的更新状态图如下:

插入更新语句设计四个部分:内存、redo log、数据表空间(t.idb)、系统表空间(ibddata1)。主要过程如下:

  1. Page1在内存中,可以直接更新内存
  2. Page2没有内存,就在内存的chane buffer中记录下这次变更
  3. 将上述两个动作记录在redo log中

redo log主要节省随机写磁盘的IO消耗(转为顺序写),change buffer主要减少的是随机读磁盘的IO消耗。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档