MySQL 09 普通索引和唯一索引,应该怎么选择?
唯一索引:字段值不能重复。
普通索引:字段值可以重复。
假设数据如下图,且字段k上的值都不重复:

接下来,从两种索引对查询语句和更新语句的性能影响来分析。
查询过程
假设查询语句为select id from T where k=5。那么首先会在字段k的索引树上找到k=5所在的数据页,然后在数据页内二分查找记录。对于普通索引和唯一索引,区别为:
普通索引,查找到满足条件的第一个记录后,会继续查找,直到找到第一个不满足
k=5的记录。唯一索引,找到第一个满足条件的记录后,就停止查找。
这个区别带来的性能差距其实是不大的。由于InnoDB的数据按数据页为单位进行读写,当找到k=5的那条记录时,它所在的数据页就都在内存里了,因此普通索引多进行的一次查找并没有多大开销。尽管有可能k=5刚好是数据页的最后一条记录,查找下一条记录需要新读取一页,但这种可能出现的概率很低,均摊到所有可能后成本可以忽略不计。
更新过程
在分析更新过程之前,先介绍change buffer。
当需要更新一个数据页,如果数据页在内存中,就直接更新;如果数据页在磁盘中,在不影响数据一致性的前提下,InnoDB会将这些更新操作缓存在change buffer中。当下次查询需要访问该数据页,会将该数据页读入内存,执行change buffer中与该页有关的操作来保证数据逻辑的正确性。
change buffer在内存中,也会被持久化到磁盘上。
将change buffer中的操作应用到原数据页,得到最新结果的过程称为merge。除了访问这个数据页会触发merge,系统有后台线程会定期merge。在数据库正常关闭的过程中,也会执行merge操作。
可以看出,如果能将更新操作先记录在change buffer,减少读磁盘的次数,语句执行速度将会加快。而且,数据读入内存需要占用buffer pool,使用change buffer还能避免占用内存,提高内存利用率。
但并不是所有条件下都可以使用change buffer。对于唯一索引,所有更新操作都必须判断该操作是否违反唯一性约束,比如要插入(4,400),就需要先判断表中是否已经有k=4的记录,因此每次更新都需要将数据页读入内存。而如果本身有读入内存的操作,那么直接更新内存即可,不需要再使用change buffer。而对普通索引,change buffer是可以使用的。
change buffer用的是buffer pool里的内存,不能无限增大。其大小可以通过innodb_change_buffer_max_size来动态设置,参数值表示占用buffer pool的百分比。
那么来看看,如果想要插入一条k=4的新纪录,InnoDB的处理流程:
对于唯一索引,找到3和5之间的位置,判断到没有冲突,插入值;
对于普通索引,找到3和5之间的位置,插入值。
看起来两者只相差一个判断,但若该记录要更新的目标页不在内存中,再对两者进行比较:
对于唯一索引,需要将数据页读入内存,判断到没有冲突,插入值;
对于普通索引,将更新记录在change buffer即可。
可以看到,这种情况下相差了一次随机磁盘IO,性能相差较大。
change buffer的使用场景
尽管change buffer能用于普通索引的场景,但并不是在所有情况下它都能起到加速作用。
这是由于merge是真正进行数据更新的时刻,而change buffer的主要目的就是将记录的变更动作缓存下来,所以在一个数据页merge前,change buffer记录的变更越多,收益越大。
对于写多读少的业务场景,页面写完后马上被访问的概率较小,意味着change buffer马上merge的概率较小,此时使用效果较好,场景业务模型如账单类、日志类系统。
而对于一个写入之后马上做查询的场景,merge的频率较高,这样随机访问IO的次数并不会减少,反而增加了change buffer的维护代价。因此,对于这种业务模式来说,change buffer反而起到了副作用。
索引选择和实践
回到之前的问题:如何选择普通索引和唯一索引。
经过上面的分析可以看到,两者在查询过程的能力几乎无差别,主要区别在更新过程。因此,建议尽量选择普通索引。如果是写入后马上查询的场景,建议关闭change buffer。
普通索引 + change buffer,对于数据量大的表的更新优化是比较明显的。特别地,在使用机械硬盘时,change buffer机制收益非常显著,因此使用机械硬盘时考虑加大change buffer。
change buffer和redo log
理解了change buffer的原理,可能会发现这和redo log有一些相似。
让我们回顾redo log的WAL机制:MySQL的更新用到了WAL(Write-Ahead Logging)技术,关键点就是先写日志,再写磁盘。具体来说,当有一条记录需要更新时,InnoDB引擎先将记录写到redo log并更新内存,这时更新就可以算完成了。之后,InnoDB会在适当的时候将这个操作记录更新到磁盘里。
接下来,使用一个例子来区分这两个概念。假设要在表上执行下面这个插入语句:
insert into t(id,k) values(id1,k1),(id2,k2);
假设在k索引树找到位置后,k1所在的数据页在内存中,而k2所在的数据页不在内存中。下图是带change buffer的更新状态图:

分析这条更新语句:
发现Page 1在内存中,直接更新内存;
发现Page 2没有在内存中,就在内存的change buffer区域,记录“我要往Page 2插入一行”这个信息;
将上述两个动作记入redo log。
做完上述动作,事务就完成了。可以发现,对于该次更新,只是写了两次内存+一次磁盘。图中的虚线箭头是后台操作,不会影响更新的响应时间。
那么此次更新之后的查询请求,会怎么处理呢?
比如要执行select * from t where k in (k1,k2),其读请求的流程图如下:

分析这条查询语句:
读Page 1时,直接从内存返回。
读Page 2时,需要先将Page 2从磁盘读入内存,然后应用change buffer,生成一个正确版本并返回结果。
因此,如果简单对比change buffer和redo log在提升更新性能上的收益的话:
redo log主要节省了随机写磁盘的IO消耗,将随机写转为了顺序写;
change buffer节省了随机读磁盘的IO消耗。
最后,做一个思考:如果某次写入使用了change buffer,如果之后主机异常重启,是否会丢失change buffer和数据?
答案是不会,因为在写完change buffer后,会把该动作也记录到redo log后,之后崩溃恢复也可以通过redo log找回。
MySQL 09 普通索引和唯一索引,应该怎么选择?的更多相关文章
- MySQL的几个概念:主键,外键,索引,唯一索引
概念: 主键(primary key) 能够唯一标识表中某一行的属性或属性组.一个表只能有一个主键,但可以有多个候选索引.主键常常与外键构成参照完整性约束,防止出现数据不一致.主键可以保证记录的唯一和 ...
- Mysql索引介绍及常见索引(主键索引、唯一索引、普通索引、全文索引、组合索引)的区别
Mysql索引概念:说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这本书1000页,有500也是目录,它当然效率低,目录是要 ...
- MySQL 普通索引、唯一索引和主索引
1.普通索引 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度.因此,应该只为那些最经常出现在查询条件(WHEREcolumn=)或排序条件(ORDERBYcolumn ...
- Mysql主键索引、唯一索引、普通索引、全文索引、组合索引的区别
原文:Mysql主键索引.唯一索引.普通索引.全文索引.组合索引的区别 Mysql索引概念: 说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不 ...
- 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择
通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...
- MySQL 笔记整理(9) --普通索引和唯一索引,应该怎么选择?
笔记记录自林晓斌(丁奇)老师的<MySQL实战45讲> (本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除) 9) --普通索引和唯一索引,应该怎么选择? 假如你在维护一个市民系统, ...
- MySQL 普通索引和唯一索引的区别
该文为< MySQL 实战 45 讲>的学习笔记,感谢查看,如有错误,欢迎指正 一.查询和更新上的区别 这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响.建议尽量选择普通索引 ...
- 如何选择普通索引和唯一索引《死磕MySQL系列 五》
系列文章 一.原来一条select语句在MySQL是这样执行的<死磕MySQL系列 一> 二.一生挚友redo log.binlog<死磕MySQL系列 二> 三.MySQL强 ...
- MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划
这篇文章主要介绍了MongoDB性能篇之创建索引,组合索引,唯一索引,删除索引和explain执行计划的相关资料,需要的朋友可以参考下 一.索引 MongoDB 提供了多样性的索引支持,索引信息被保存 ...
- Sql Server 索引之唯一索引和筛选索引
唯一索引(UNIQUE INDEX) 当主键创建时如果不设置为聚集索引,那么就一定是唯一的非聚集索引.实际上,唯一索引,故名思议就是它要求该列上的值是唯一的.唯一索引能够保证索引键中不包含重复的值, ...
随机推荐
- H5 电商新势力崛起:ZKmall模板商城 H5 版本的高性能开发秘籍
H5电商新势力的崛起中,ZKmall模板商城H5版本以其高性能和灵活性脱颖而出.以下是ZKmall模板商城H5版本的高性能开发秘籍,结合技术选型.架构优化与核心实践,为全场景电商应用提供高效解决方案: ...
- 武汉工程大学2020GPLT选拔赛(重现赛)
L2-4 缘之空 1.使用倍增法求最近公共祖先,然后利用公共祖先计算两点的树上距离 2.但是此题并没有提供根节点,所以要先找到根节点以后才可以进行倍增法求lca /** - swj - * /> ...
- JDBC-增删查改操作
使用场景:测试家族族长分成时需要批量添加家族流水记录,但手动添加和SQL语句添加较为麻烦 操作步骤 运行环境:Java8+IDEA 1.打开IDEA 点击File->New->Projec ...
- RocketMQ的Producer是如何发送消息的
RocketMQ 的 Producer 发送消息过程涉及多个步骤,包括初始化.消息创建.发送方式选择 1.Producer初始化 首先,我们需要创建并初始化一个Producer示例 这段代码完成了以下 ...
- 【杂谈】死锁?NO,时间跳跃!
在日常开发或线上运维中,我们经常会遇到各种数据库异常,例如超时.死锁等.但有些问题,表面看似平常,背后却藏着意想不到的原因. 今天就分享一次由服务器时间跳跃引发的 MySQL 获取锁超时问题的排查过程 ...
- .NET 原生驾驭 AI 新基建实战系列(三):Chroma ── 轻松构建智能应用的向量数据库
在人工智能AI和机器学习ML迅猛发展的今天,数据的存储和检索需求发生了巨大变化.传统的数据库擅长处理结构化数据,但在面对高维向量数据时往往力不从心.向量数据库作为一种新兴技术,专为AI应用设计,能够高 ...
- fiddler断点应用
一.作用 1.模拟网络中断 2.断点时篡改数据 3.测试时做一些极端测试 二.断点步骤 1.全局断点 1)全局断点的两种方式 点击状态栏空白框,点击一下请求前断点,两下请求后断点,三下取消断点 Rul ...
- 【完结】【一本通提高】KMP做题记录
题目编号 标题 估分 正确 提交 Y 2076 Problem A [一本通提高篇KMP]剪花布条 --- 156 293 Y 2077 Problem B [一本通提高篇KMP]Radio Tr ...
- DeepSeek 多模态模型 Janus-Pro 本地部署
一.概述 Janus-Pro是DeepSeek最新开源的多模态模型,是一种新颖的自回归框架,统一了多模态理解和生成.通过将视觉编码解耦为独立的路径,同时仍然使用单一的.统一的变压器架构进行处理,该框架 ...
- k8sd之pod生命周期
pod生命周期: 状态:pending 挂起 没有节点满足条件 running 运行 Failed sucess unkonwn pod生命周期中的重要行为: 初始化容器 容器探测:liveness ...