我秃了!唯一索引、普通索引我该选谁?
小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL江湖路 | 专栏目录
提到唯一索引
和普通索引
,相信大家都不陌生,当同事小姐姐问你这俩有什么区别时?或许你会脱口而出:“这还用问?见名知意啊,一个是允许字段重复,一个不允许存在重复数据!”
是否解决小姐姐的疑问我不知道,但你在同事心目中,肯定不是啥好玩意儿~ 要知道,一眼就看出的答案,一般不会有人问,除非问傻子~
那么当你处理一张市民信息表时,其中一列为市民的身份证号信息,你会怎么选择哪个索引?为什么?
对于一个经历过风风雨雨、日日夜夜的程序员来说,需要你考虑的东西可不仅是重不重复这类问题,而是…
开个玩笑~~应当结合实际情况,对各个场景进行综合考虑。
其实,如果在业务代码中保证了不会写入重复的身份证号,那么这两个选择逻辑上都是正确的。但是在SELECT和DML场景中,唯一索引和普通索引却有很多不同。
1、在SELECT中,唯一索引和普通索引的区别
本文测试引擎选择我们最常用的InnoDB,版本为MySQL8.0;
假设,执行查询的语句是:
select id from T where id_card = 666;
(身份证太长,咱们用简单数据做演示)我们知道,MySQL的InnoDB采用的是B+树实现的索引结构,查找过程从B+树的树根起,按层搜索到666
所在的叶子节点,然后取出该节点所在的数据页,把数据页读到内存后,通过二分法在数据页中定位id_card=666的行数据。
B+ 树的查找过程如上图:
将磁盘块1从磁盘加载到内存
,发生一次IO ,在内存中使用二分查找方式找到 666 在600和700 之间,锁定磁盘块1的P2 指针。- 通过磁盘块1 的 P2 指针地址把
磁盘块3 加载到内存
,发生第二次IO ,锁定磁盘块3 的 P2 指针 - 通过磁盘块3 的P2指针加载
磁盘块7到内存
,发生第三次 IO,同时根据二分查找找到666 查询结束。
普通索引和唯一索引的定位方式:
- 普通索引:查到第一条id_card=666 后,然后继续往后查找直到碰到第一个
id_card<>666
的记录时,结束。 - 唯一索引:由于索引定义了唯一性,查找到第一个满足条件的记录后,直接结束。
两者在查询方面的性能差距微乎其微。
对于普通索引多的那一次操作,因为本身就是以数据页为单位读进内存,数据页大小默认16KB(大概1000行),要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算。当然,不可避免查询的数据是该数据页的最后一位,这样还要再读下一块数据页,算法会复杂一些。
但你知道的,这种概率很小,我们程序员要相信逆墨菲定律:大概率不会出现且未被发现的BUG,在难以改动的前提下,你就当不知道就完了,发生了又能咋地?有测试顶着呢!
有同学问我了:
普通索引为什么要继续向下查找?
继续向下查找的原因是由于普通索引允许重复值,且B+Tree是天然有序的。SQL中并没有指定limit 1
,所以他还要往下查,看是否有同条件的数据一起返回,直到查到第一条不满足条件的数据为止。
2、在DML中,唯一索引和普通索引的区别
ding!这是本篇文章的重点,在看之前,我们需要先了解什么是change buffer
。
了解MySQL机制的同学们知道,当执行 DML(INSERT、UPDATE、DELETE)等操作时,InnoDB会利用 change buffer进行加速写操作
,可以将写操作的随机磁盘访问调整为局部顺序操作
,而在机械硬盘时代,随机磁盘访问(随机I/O)
也是数据库操作中的最耗性能的硬伤。当普通索引(非唯一索引)
的数据页发生写操作时,把操作内容写到内存中的change buffer后就可以立刻返回(执行完成)了。
这里我以UPDATE操作为例
,当需要更新某一行数据时,会先判断该行所在数据页是否在内存中,如果在就直接在内存数据页中更新,如果这个数据页没有内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些UPDATE操作
缓存在 change buffer
中,这样就不需要从磁盘读入数据页,当有SQL查询需要访问这个数据页的数据时
,将数据页读入内存后,然后先执行 change buffer 中与这个页的相关UPDATE操作
,通过这种方式保证这个数据页的逻辑正确性
。
可见,change buffer是会被从内存持久化到磁盘中的
,将 change buffer 中的操作应用到原数据页,得到最新结果的过程被称为 merge
。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作,相当于刷脏页啦(把已修改的数据更新到实际数据文件中)。
触发merge的操作主要有以下几种(你该记住的点
):
- 有SQL线程访问这个数据页;
- master thread线程每秒或每10秒进行一次
merge change buffer
的操作; - 在数据库正常关闭的时候。
小朋友,你是否有很多问号??DB服务器宕机,数据不是就丢了?这就得redo log + binlog来保证了,可以参考作者另一篇文章《听我讲完redo log、binlog原理,面试官老脸一红》,本篇不再赘述。
跑远了?言归正传~~上文提到普通索引(非唯一索引)
会使用到change buffer进行加速写操作,你是不是已经get到点了呢~
是的,唯一索引不会使用 Change buffer
,如果索引设置了唯一属性,在进行插入或者修改操作时,InnoDB 必须进行唯一性检查
,如果不读取索引页到缓冲池,无法校验索引是否唯一,如果都把索引页读到内存了,那直接更新内存会更快,就没必要使用change buffer了。
对于普通索引(非唯一索引)
的DML操作来说,当待更新的数据页在内存中时,找到前值和后值的区间插入即可;当待更新的数据页在不在内存中时,直接把操作写到Change buffer就完事儿了。舒服!而
对于唯一索引
,当待更新的数据页在不在内存中时,索引每次都得把数据页读到内存中判断唯一性,将数据从磁盘读入内存涉及大量随机IO
的访问,慢的一批,当遇到高频写操作时??唉,别想了,难受!
到这里,相信你对普通索引和唯一索引的取舍有了一定的概念,普通索引和唯一索引在查询能力上是没差别的
,主要考虑的是更新
的影响。还得结合实际业务场景来判断,如果是读取远大于更新和插入的表
,唯一索引和普通索引都可以,但是如果业务需求相反
,个人觉得应该使用普通索引,当然如果是那种更新完要求立即可见的需求,就是刚更新完就要再查询的,这种情况下反而不推荐普通索引,因为这样会频繁的产生merge操作,起不到change buffer的作用,反而需要额外空间来维护change buffer就有点得不偿失了。
当我们使用普通索引,尤其在使用机械盘的场景下,尽量把change buffer开大从而确保数据的写入速度。最后,通过列举一下 change buffer 的配置,结束今天的分享,相信看到这里的都是有心人,也是喜爱MySQL的崽子,记得不要吝啬你的点赞哦~~
change buffer 配置
- innodb_change_buffer_max_size% 配置写缓冲的大小,占整个缓冲池的比例,默认值是25%,可以通过修改该值提高InnoDB写效率,最大值是50%。
mysql> show variables like '%innodb_change_buffer_max_size%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25 |
+-------------------------------+-------+
1 row in set (0.00 sec)
- innodb_change_buffering配置是否缓存辅助索引页的修改,默认为 all,即缓存 INSERT/DELETE/UPDATE等DML操作。
mysql> show variables like '%innodb_change_buffering%';
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| innodb_change_buffering | all |
+-------------------------+-------+
1 row in set (0.00 sec)
MySQL系列文章汇总与《MySQL江湖路 | 专栏目录》
往期热门MySQL系列文章
:
- 原创 | MySQL中特别实用的几种SQL语句送给大家
- 原创 | SQL优化最干货总结 - MySQL(2020最新版)
- 原创 | 为什么大家都说SELECT * 效率低
- 原创 | 面试让HR都能听懂的MySQL锁机制,欢声笑语中搞懂MySQL锁
- 原创 | MySQL中的 utf8 并不是真正的UTF-8编码 ! !
- 原创 | MySQL数据中有很多换行符和回车符!!该咋办?
- 原创 | delete后加 limit是个好习惯么
我秃了!唯一索引、普通索引我该选谁?相关推荐
- 唯一聚集索引上的唯一和非唯一非聚集索引
在上篇文章里,我讨论了唯一和非唯一聚集索引的区别.我们已经知道,SQL Server内部使用4 bytes的uniquifier来保证非唯一聚集索引行唯一.今天我们来看下唯一聚集索引上,唯一和非唯一非 ...
- 索引键的唯一性(3/4):唯一聚集索引上的唯一和非唯一非聚集索引
在上篇文章里,我讨论了唯一和非唯一聚集索引的区别.我们已经知道,SQL Server内部使用4 bytes的uniquifier来保证非唯一聚集索引行唯一.今天我们来看下唯一聚集索引上,唯一和非唯一非 ...
- 数据库-索引-普通索引-唯一索引
MySQL 索引 MySQL索引的建立对于MySQL的高效运行是很重要的,索引可以大大提高MySQL的检索速度. 索引分单列索引和组合索引.单列索引,即一个索引只包含单个列,一个表可以有多个单列索引, ...
- 普通索引 唯一索引 主键索引 候选索引
普通索引 最基本的索引类型,没有唯一性之类的限制.普通索引可以通过以下几种方式创建: 创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表): 修改 ...
- sqlite 复合唯一索引_SQLite 索引(Index)
索引(Index)是一种特殊的查找表,数据库搜索引擎用来加快数据检索.简单地说,索引是一个指向表中数据的指针.一个数据库中的索引与一本书后边的索引是非常相似的. 例如,如果您想在一本讨论某个话题的书中 ...
- SQLServer之创建唯一非聚集索引
创建唯一非聚集索引典型实现 唯一索引可通过以下方式实现: PRIMARY KEY 或 UNIQUE 约束 在创建 PRIMARY KEY 约束时,如果不存在该表的聚集索引且未指定唯一非聚集索引,则将自 ...
- 数据库表的主键、唯一约束和索引
目录 1.MySQL的主键. 2.MySQL的唯一约束. 3.MySQL的索引. 4.主键.唯一约束和唯一索引的区别. 1.MySQL 的 主键. "主键" 的完整称呼是 &quo ...
- mysql 主键 索引类型_MYSQL常见索引类型(主键索引/唯一索引/普通索引/组合索引)...
在数据量特别大的数据库表中,对字段建立索引可以大大提高查询速度.通过善用这些索引,可以令MySQL的查询和运行更加高效. 一.MySQL常见的索引类型如下 MySQL常见索引有:主键索引.唯一索引.普 ...
- mongo 唯一约束索引_mongodb索引详解(Indexes)
索引介绍 索引在mongodb中被支持,如果没有索引,mongodb必须扫描每一个文档集合选择匹配的查询记录.这样扫描集合效率并不高,因为它需要mongod进程使用大量的数据作遍历操作. 索引是一种特 ...
- mysql 联合索引 唯一_mysql 联合索引和唯一索引
一般来说.如果有where a=? and b=? and c=? 的语句. 如果表也有DML, 我一般只在a 上建索引. 这也是代价平衡的结果. 一方面 只在a 上建索引那么是 index ran ...
最新文章
- AI一分钟 | 豪华太空酒店预计2022年前开业;彭蕾卸任蚂蚁金服董事长,井贤栋接任;京东推出一秒能写千条文案的AI系统
- 如何看待团队合作这件事?
- 照片你随便拍,「光影」我任意调,MIT谷歌新研究,器材党老法师看了会沉默...
- maven+springMVC+Eclipse建立工程框架
- C# 根据中文得到全拼
- linux命令 查看某安装包是否已安装
- 微信小程序实战开发视频
- 登山(信息学奥赛一本通-T1283)
- POJ 2847 Widget Factory
- python基础序列化文件的读取(十六)
- 【设计模式】适配器模式(Adapter Pattern)
- RocketMQ如何应对每天1500亿条的数据处理
- Cubase Elements v11.0.0 WiN 23GB含音色库 中文完整版编曲录音软件
- 在ubuntu9.10下 安装nvidia GT130M最新驱动190.42版本
- mysql CONCAT函数 用于隐藏银行卡号码
- 云原生微服务架构实战精讲第八节 访问控制与更新策略
- flutter 返回桌面
- Python绘画可爱的哆啦A梦
- docker连接wind10本地pycharm pro
- 订阅号消息 服务号 信息推送
热门文章
- OJ 1308 让人头疼的“双十一”
- 时寒冰:中国房价下跌序幕刚刚拉开
- 必应搜索器主页图片网址
- 您的浏览器暂不支持计算机上传文件的大小,电脑中谷歌浏览器无法上传图片的解决方法...
- 树莓派(ubuntu系统)连接后使用HDMI-VGA,VGA无信号
- sklearn机器学习:泰坦尼克号幸存者的预测
- 阅读书籍:Monte Carlo Methods(第一章 Introduction to Monte CarloMethods)
- fckeditor文档库
- linux下同一个tomcat部署多个项目 同一个端口
- Dreamweaver自带流体布局+自己添加,后附效果,不知代码有错误没?请行家指正!多谢先