我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MySQL唯一索引和普通索引选哪个?

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MySQL唯一索引和普通索引选哪个?

想象这样一个场景,在设计一张用户表时,每人的身份证号是唯一的,需要搜索。但由于身份证号字段较大,不好将其作为主键。在业务代码已经保证插入身份证唯一的情况下,可以选择建立唯一索引和普通索引,这时该如何选择呢?接下来,将从查询和更新的执行过程进行分析。

查询过程

假设 k 是表 t 上的索引,在搜索 select id from t where k=5 时,会先从 k 这棵 B+ 的树根开始,按层搜索叶子节点,找到 k=5 的数据页,然后在数据页内容进行二分法定位。

对于普通索引,找到 k=5 的记录后,会继续向下查找一个,直到碰到第一个不是 5 的记录结束。

对于唯一索引,由于取值唯一,找到后直接停止。

由于 InnoDB 是按照数据页为单位(数据页默认 16 KB)进行读写的,在读取一条数据时,会将整个数据页整体读到内存。 在读入内存的数据页中,如果包含 k=5 的记录,在查询的情况下,唯一索引比普通索引多了一次查找和判断的过程,可以忽略。

如果 k=5 是当前数据页的最后一条,就需要在读取下一个数据页。但这发生的概率较低,也可以忽略。

所以总得来说,普通索引和唯一索引在查询的过程中差异不大。

change buffer

在分析唯一索引和普通索引的影响前,先来认识一下 change buffer 这个结构。

什么是 change buffer ?

在执行更新操作时,如果要更新的数据页在内存中就直接更新,否则的话,在不影响数据一致性的前提下,InnoDB 会将更新操作缓存在 change buffer 中,从而省去了从磁盘读取数据页的过程。在下次查询操作读取到恰好需要更新的数据页时,会将 change buffer 的更新语句执行,写入数据页。将操作应用到硬盘的过程叫 merge. 后台线程会定期 merge 或 数据库正常关闭时,也会进行 merge 操作。

merge 的执行流程:

  1. 从磁盘读入老版本数据页。
  2. 从 change buffer中找出和该数据页关联的记录,依次应用,得到新版数据页。
  3. 写 redo log,记录数据的变更和 change buffer 的变更。

change buffer 实际上是可以持久化到硬盘中的数据,也就是说在内存和硬盘上都 change buffer 的存在。change buffer 之前叫 insert buffer,开始只对 insert buffer 有优化,后来加上了对 delete 和 update 的支持,进而改名叫 change buffer。

可以看到,先将更新操作记录在 change buffer,减少了将磁盘数据页读取到内存的过程,语句的执行速度会有很明显的提升。同时,将数据读入内存,会占用 buffer pool 内存,所以减少读操作,还提高了内存使用率。

Buffer Pool 是内存中的一个区域,InnoDB 在访问表和索引数据时会在其中进行缓存。允许在内存中直接更新经常使用的数据,来加快处理速度。在一些专用的服务器上,会将 80% 的物理内存分为 buffer pool.

可以通过 innodb_change_buffer_max_size 来设置 change buffer 占用 buffer pool 的大小。

change buffer 应用场景?

如上面提到,change buffer 预先保存了更新记录,减少了读取数据页的过程,从而提高性能。也就是说如果 change buffer 中针对不同的数据页如果包含的更新记录越多,其实收益也就越大。

因此对于写多读少的业务(更新完立即查询)change buffer 发挥的作用也就越大。如常见的账单类,日志类等系统。

如果业务是更新完立即查询,虽然可以将更新记录放在 change buffer 中,但由于之后要马上查询数据页,所以会立即触发 merge 过程。这样随机访问 IO 次数并不会减少,反而增加了 change buffer 的维护代价,起到反效果。

更新过程

对于唯一索引来说,所有的更新操作都需要判断是否违反唯一性约束。所以必须把所需要的数据页读入内存,然后直接更新就可以,不需要使用 change buffer. 所以 change buffer 只对普通索引有用。

具体分析下,对于一张表插入一个新记录:

如果新记录要更新的数据页在内存中:

对于唯一索引,找到合适的位置,判断有没有冲突,插入值,语句结束。

对于普通索引:找到位置,插入值,语句结束。

所以数据页在内存时,唯一和普通索引就差一个判断的过程。可以忽略。

如果新记录要更新的数据页不在内存中:

对于唯一索引,将数据页读入内存,判断冲突,插入,语句结束。

对于普通索引,将语句记录在 change buffer 中,语句结束。

由于从磁盘到内存涉及随机 IO 访问,是数据库成本最高的操作之一。普通索引比唯一索引减少的读入操作,可以有很好的性能提升。

唯一或普通索引的选择

通过在查询和更新方面,两者的比较。我们知道,在查询过程中,除了极特殊情况,其实两者的差异并不大。

主要的差异是在更新过程中,要更新的数据页并不在内容中的情况。这时唯一索引,由于需要唯一性检查,不能利用 change buffer. 多了从磁盘到内容读取数据的过程,其中涉及随机 IO 的访问,相对来说效率就低了。

所以如果业务需要更新不错的性能,这时可以选用普通索引。当然一切都是建立在能保证数据准确性的前提下。

当如果更新后来紧接着查询操作,可以考虑关掉 change buffer. 其他的情况,change buffer 都能有很好的提升。

特别针对机械硬盘,change buffer 效果很显著。

redo log 和 change buffer 的比较

InnoDB 中 redo log 的出现使其具有了 crash-safe 的能力,同时还提高了效率,通过 WAL 先写日志,再写磁盘。

而 change buffer 是节省了从磁盘读入数据页到内存的随机IO过程。

下面通过一条插入语句来分析下两者间的关系:


mysql> insert into t(id,k) values(id1,k1),(id2,k2);

假设 k 为普通索引,k1 所插入的数据页在内存中, k2 不在。

执行插入操作时,主要涉及了图中这四部分的内容:

InnoDB buffer pool:内存区域

redo log:日志

system table space(ibdata1):系统表空间

data(t.idb): 数据表空间

innodb_file_per_table 开启时,表被创建在独立的表空间下,否则的话被创建在系统的表空间下。

执行过程如下:

  1. k1 所在的 page1 在内存中,直接更新内存
  2. k2 所在的 page2 不在内存中,记录在 change buffer.
  3. 将 k1 和 k2 的操作记录在 redo log.
  4. 提交事务。

可以看到这条更新语句(包括插入,删除,更新操作)执行成本很低,两次写入内存,1次顺序写入磁盘。虚线的操作,是后台操作,不影响响应时间。

再来看一条查询语句:


select * from t where k in (k1, k2)

假设读语句发生在更新语句不久,内存数据还在,此时读操作就和系统表空间和 redo log 无关。

执行过程:

  1. 读取 k1 所在的 page1,在内存中,直接返回。注意,并没有读磁盘上的数据,而且磁盘上的数据还有可能是之前的版本的。
  2. 读取 k2 所在的 page2,这时需要将 page2 从磁盘加载到内存,并应用 change buffer 的内容,然后返回正确的结果。从这里也能看出,change buffer 不适用于更新完立马去读的情况。

总结下 redo log 和 change buffer 的关系:

存储位置:change buffer 也会持久化在硬盘里,但保存在系统表空间 ibdata1 里。而 redo log 是单独的文件。

记录内容:change buffer 记录的是更新操作的内容,而 redo log 记录的是普通数据页的修改和 change buffer 的改动。

同步磁盘过程:同步内存中数据页的修改时通过 merge 操作进行的,而不是根据 redo log.

从更新的过程来看: redo log 将随机写磁盘的 IO 转换成了顺序写,而 change buffer 则是节省了随机读磁盘的 IO 消耗。

如果服务器异常掉电,会不会导致 change buffer 丢失?

并不会,因为 change buffer 中的数据已经被记录到 redo log 中,所以不会丢失。

由于 change buffer 一部分数据在磁盘,一部分在内存。对于在磁盘的数据已经 merge 所以不会丢失。
对于在内存中的数据:

  1. 如果 change buffer 写入,但 redo log 未提交,binlog 未提交,事务会回滚,这部分数据不存在。
  2. 如果 change buffer 写入,redo log 写入,binlog 写入,并已提交,不会丢失。从 redo log 直接恢复。
  3. 如果 change buffer 写入,redo log 写入但未 commit,binlog 写入,从 binlog 恢复 redo log 再恢复 change buffer.

参考资料

Buffer Pool

以上就是MySQL唯一索引和普通索引选哪个?的详细内容,更多关于MySQL唯一索引和普通索引的资料请关注自学编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MySQL唯一索引和普通索引选哪个?

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL唯一索引和普通索引选哪个?

想象这样一个场景,在设计一张用户表时,每人的身份证号是唯一的,需要搜索。但由于身份证号字段较大,不好将其作为主键。在业务代码已经保证插入身份证唯一的情况下,可以选择建立唯一索引和普通索引,这时该如何选择呢?接下来,将从查询和更新的执行过程进
2022-05-28

普通索引 PK 唯一性索引,用哪个好?

我们建索引的时候,有全文索引、主键索引、唯一性索引、普通索引等,前面两个好理解好区分,大家都知道啥时候用,后面两个该如何区分呢?

MySQL 普通索引和唯一索引的区别详解

1 概念区分普通索引和唯一索引普通索引可重复,唯一索引和主键一样不能重复。 唯一索引可作为数据的一个合法验证手段,例如学生表的身份证号码字段,我们人为规定该字段不得重复,那么就使用唯一索引。(一般设置学号字段为主键)主键和唯一索引主键保证数
2022-05-25

我秃了!唯一索引、普通索引我该选谁?

提到唯一索引和普通索引,相信大家都不陌生,当同事小姐姐问你这俩有什么区别时?或许你会脱口而出:“这还用问?见名知意啊,一个是允许字段重复,一个不允许存在重复数据!”

普通索引和唯一索引的执行过程

这里普通索引和唯一索引的情况有所不同查询过程对于普通索引来说,查找到满足条件的第一个记录后,需要查找下一个记录, 直到碰到第一个不满足条件的记录。对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索这个不同带来的性能差距会有多
普通索引和唯一索引的执行过程
2016-04-05

​oracle唯一索引和普通索引有什么不同

Oracle索引差异唯一索引与普通索引差异在于:数据完整性:唯一索引强制唯一性,普通索引不保证。约束:唯一索引隐含UNIQUE约束,普通索引需另定义。存储空间:唯一索引占用更多空间,普通索引占用更少。维护成本:唯一索引维护成本更高,普通索引维护成本较低。查询性能:唯一索引在独特列查询中性能优越,普通索引在非唯一列查询中性能更佳。使用场景:唯一索引用于保证数据唯一性,普通索引用于提高查询性能。优点:唯一索引保证数据唯一性,普通索引提高查询性能。缺点:唯一索引维护成本高,普通索引不保证唯一性。选择指南:根据数
​oracle唯一索引和普通索引有什么不同
2024-04-12

普通索引与唯一索引在MySQL 中有什么区别

这篇文章给大家介绍普通索引与唯一索引在MySQL 中有什么区别,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1 概念区分普通索引和唯一索引普通索引可重复,唯一索引和主键一样不能重复。 唯一索引可作为数据的一个合法验证手
2023-06-06

MySQL:为什么说应该优先选择普通索引,尽量避免使用唯一索引

今天我们来聊一聊,普通索引和唯一索引的使用场景,以及为什么说推荐大家优先使用普通索引,尽量避免使用唯一索引。

MYSQL联合唯一索引

https://blog.csdn.net/weistin/article/details/79698996
MYSQL联合唯一索引
2019-08-28

MySQL中的聚簇索引、非聚簇索引、联合索引和唯一索引是什么

今天小编给大家分享一下MySQL中的聚簇索引、非聚簇索引、联合索引和唯一索引是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下
2023-04-21

MySQL中的聚簇索引、非聚簇索引、联合索引和唯一索引详细介绍

目录一、索引类型二、聚簇索引和非聚簇索引三、覆盖索引四、联合索引最左前缀匹配原则索引下推五、唯一索引一、索引类型索引根据底层实现可分为B-Tree索引和哈希索引,大部分时候我们使用的都是B-Tree索引,因为它良好的性能和特性更适合于构建
2023-04-19

MySQL 加锁范围三——普通索引和普通字段

普通索引等值查询,因为不能确定唯一性,所以即使定位到记录,也是会向后查询,直到查询到不为该值的记录,从而锁定该值的区间;普通索引的锁也是加载该索引上的,如果涉及到存在的记录,会对该主键加行锁;普通索引的范围查询,同样出现 next-key

编程热搜

目录