普通索引

这是最基本的索引类型,而且它没有唯一性之类的限制。

唯一性索引

这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。

这两种索引的运行原理

查询过程

对于普通索引来说,查找到满足条件的第一个记录后,需要查找下一个记录,直到碰到第一个不满足条件的记录。

对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

所以在这里你感觉用唯一性索引会快一些,毕竟少了一个步骤。但是这个不同带来的性能差距微乎其微。

你知道的,InnoDB 的数据是按数据页为单位来读写的。也就是说,当需要读一条记录的时候,并不是将这个记录本身从磁盘读出来,而是以页为单位,将其整体读入内存。在 InnoDB 中,每个数据页的大小默认是 16KB。

因为引擎是按页读写的,所以说,当找到符合条件的记录的时候,它所在的数据页就都在内存里了。那么,对于普通索引来说,要多做的那一次“查找和判断下一条记录”的操作,就只需要一次指针寻找和一次计算。

当然也会有特殊情况,就是符合条件的记录正好处于数据页的最后一个,那往下查找的操作就会拿下一个数据页放进内存,这个时候就会慢了,但是一个整型字段,一个数据页可以放进千的key,所以这个概率很低。

更新过程

Change buffer。

两种索引更新过程主要差别就是因为Change buffer。

Change buffer的主要目的是将对二级索引的数据操作缓存下来,以此减少二级索引的随机IO,并达到操作合并的效果。

当InooDB更新一个数据页的时候有2中情况:

  1. 数据页在内存中,此时直接更新。
  2. 数据页不在内存中,这时候 InooDB 会将这些更新操作缓存在 change buffer 中,然后在下次需要访问这个数据页的时候,将数据页放入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。这种情况在更新操作时省去了把数据页从磁盘读入内存这一步,而是在以后访问这个数据页的时候再做更新操作。

显然,如果能够将更新操作先记录在 change buffer,减少读磁盘,语句的执行速度会得到明显的提升。而且,数据读入内存是需要占用 buffer pool 的,所以这种方式还能够避免占用内存,提高内存利用率。

change buffer 用的是 buffer pool 里的内存,因此不能无限增大。change buffer 的大小,可以通过参数 innodb_change_buffer_max_size 来动态设置。这个参数设置为 50 的时候,表示 change buffer 的大小最多只能占用 buffer pool 的 50%。

buffer pool: Innodb维护了一个缓存区域叫做Buffer Pool,用来缓存数据和索引在内存中。Buffer Pool可以用来加速数据的读写,如果Buffer Pool越大,那么Mysql就越像一个内存数据库,所以了解Buffer Pool的配置可以提高Buffer Pool的性能。

需要说明的是,虽然名字叫作 change buffer,实际上它是可以持久化的数据。也就是说,change buffer 在内存中有拷贝,也会被写入到磁盘上。
将 change buffer 中的操作应用到原数据页,得到最新结果的过程称为 merge。除了访问这个数据页会触发 merge 外,系统有后台线程会定期 merge。在数据库正常关闭(shutdown)的过程中,也会执行 merge 操作。

这个 change buffer普通索引会用到,唯一索引用不到,因为唯一索引的更新操作之前都要判断唯一性,所以在判断这步已经把数据页放在了内存里,所以之后的更新操作就直接在内存里操作了,内存更新更快,没必要用change buffer了。

所以,普通索引会用到 change buffer。

索引具体的处理流程

清楚了change buffer然后模拟一个场景来看一下两种索引具体的处理流程是怎样的。

如果要在这张表中插入一个 id=5的新纪录,InnoDB 的处理流程是怎样的。

第一种情况:目标数据页在内存中。

  • 唯一索引:找到 4 和 6 之间的位置,判断到没有冲突,插入这个值,语句执行结束;
  • 普通索引:找到 4 和 6 之间的位置,插入这个值,语句执行结束。

这样看来,普通索引和唯一索引对更新语句性能影响的差别,只是一个判断,只会耗费微小的 CPU 时间。

第二种情况是:目标数据页不在内存中

  • 唯一索引:需要将数据页读入内存,判断到没有冲突,插入这个值,语句执行结束;
  • 普通索引:则是将更新记录在 change buffer,语句执行就结束了。

主要区别就是唯一索引需要把磁盘中的数据页放入内存。就是这步影响了性能。

将数据从磁盘读入内存涉及随机 IO 的访问,是数据库里面成本最高的操作之一。change buffer 因为减少了随机磁盘访问,所以对更新性能的提升是会很明显的。

但是普通索引用change buffer起到加速作用也是有应用场景的。

因为 merge 的时候是真正进行数据更新的时刻,而 change buffer 的主要目的就是将记录的变更动作缓存下来,所以在一个数据页做 merge 之前,change buffer 记录的变更越多(也就是这个页面上要更新的次数越多),收益就越大。

由此看来就是对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。

所以反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。所以,对于这种业务模式来说,change buffer 反而起到了副作用。

索引使用选择

从上面的内容来说,这两类索引在查询能力上是没差别的,主要考虑的是对更新性能的影响。所以,我建议你尽量选择普通索引。
如果所有的更新后面,都马上伴随着对这个记录的查询,那么你应该关闭 change buffer。而在其他情况下,change buffer 都能提升更新性能。

在实际使用中,你会发现,普通索引和 change buffer 的配合使用,对于数据量大的表的更新优化还是很明显的。特别地,在使用机械硬盘时,change buffer 这个机制的收效是非常显著的。所以,当你有一个类似“历史数据”的库,并且出于成本考虑用的是机械硬盘时,那你应该特别关注这些表里的索引,尽量使用普通索引,然后把 change buffer 尽量开大,以确保这个“历史数据”表的数据写入速度。这时候,归档数据已经是确保没有唯一键冲突了。要提高归档效率,可以考虑把表里面的唯一索引改成普通索引。

唯一索引使用的问题,主要是纠结在“业务可能无法确保”的情况。
首先,业务正确性优先。如果业务不能保证数据的唯一性,或者业务就是要求数据库来做约束,那么没得选,必须创建唯一索引。本篇文章的意义在于,如果碰上了大量插入数据慢内存命中率低的时候,可以给你多提供一个排查思路。

MySQL唯一索引和普通索引运行原理和使用选择相关推荐

  1. Mysql查询语句执行过程及运行原理

    Mysql查询语句执行原理 数据库查询语句如何执行? DML语句首先进行语法分析,对使用sql表示的查询进行语法分析,生成查询语法分析树. 语义检查:检查sql中所涉及的对象以及是否在数据库中存在,用 ...

  2. mysql是如何管理数据结构_MySQL索引背后的数据结构和原理

    这是我看到的一篇博客,讲得非常详细,分享给大家:http://blog.codinglabs.org/articles/theory-of-mysql-index.html Abstract: 本文以 ...

  3. mysql匹配数据结构_MySQL索引背后的数据结构及原理

    前两天经历了武汉一行腾讯面试,数据库索引是一个面试热点,在此搜集相关资料,以备学习之用. 下面是一位牛人写得关于数据库索引的精品之作,因为很好,不敢修饰,转载至此与博友共享. 本文以MySQL数据库为 ...

  4. MySQL索引的数据结构及算法原理

    本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree ...

  5. MySQL索引机制:索引分类、索引的实现原理、索引的优化 - 公开课笔记

    概要 oracle市场份额在降低,mysql变得越来越重要 样本数据可以使用 sakila 数据库 你会怎么设计索引? 加索引目的是快速查找数据,最终要快速从文件中快速获取一条记录. 如果使用id+偏 ...

  6. access建立两个字段唯一索引_数据库索引原理及优化

    微信公众号:云计算通俗讲义 持续输出技术干货,欢迎关注! 通过本文你将了解: 概述 分类 索引底层实现原理 基本操作 索引失效 索引优化 01 概述 索引是帮助MySQL高效获取数据的排好序的数据结构 ...

  7. mysql 创建唯一索引_Mysql普通索引和唯一索引的选择分析

    假设一个用户管理系统,每个人注册都有一个唯一的手机号,而且业务代码已经保证了不会写入两个重复的手机号.如果用户管理系统需要按照手机号查姓名,就会执行类似这样的 SQL 语句: select name ...

  8. mysql 唯一索引_面试官:谈谈你对mysql索引的认识?

    引言 大家好,我渣渣烟.我曾经写过一篇<面试官:讲讲mysql表设计要注意啥>,当时写完后,似乎效果还行! 于是呢,决定再来一个mysql的数据库专题,这篇我们就来谈谈关于索引方面的mys ...

  9. mysql的底层数据结构_MySQL索引底层数据结构实现原理

    MySQL索引背后的数据结构及算法原理 一.定义 索引定义:索引(Index)是帮助MySQL高效获取数据的数据结构. 本质:索引是数据结构. 二.B-Tree m阶B-Tree满足以下条件: 1.每 ...

最新文章

  1. 合并工具_分享一个SM to HISM合并工具
  2. 利用python脚本(re)抓取美空mm图片
  3. 使用OpenCV python模块读取图像并将其另存为灰度系统
  4. 前端学习(1484):json-server工具使用
  5. __declspec(naked)和__asm编写实践总结
  6. 处理大数必选BigInteger(记洛谷P1009题WA的经历,Java语言描述)
  7. 训练日志 2018.9.12
  8. IBM 开源处理加密数据的工具集
  9. 电脑访问不了虚拟机ftp服务器,解决win环境下访问本机虚拟机中centos7 ftp服务器的问题...
  10. java前后端分离是否会成为趋势
  11. 软件加入使用时间_2020年,加入“midi音乐制作讲堂”内部会员,学音乐制作变得更简单...
  12. 【控制】动力学建模举例 --> 牛顿-欧拉法
  13. 4个最受欢迎的大数据可视化工具
  14. 采用R/S分析法的Hurst指数估计算法——Python实现
  15. [Maven实战-许晓斌]-[第二章]-2.7-2.8 Mave安装的最优建议和安装小结
  16. DispatchQueue (SwiftUI Dispatch 中文手册)
  17. C语言入门——常见数据类型取值范围
  18. 2022-02-15:扫地机器人。 房间(用格栅表示)中有一个扫地机器人。 格栅中的每一个格子有空和障碍物两种可能。 扫地机器人提供4个API,可以向前进,向左转或者向右转。每次转弯90度。 当扫地机
  19. ddt数据驱动 python接口 xls_013 python接口 数据驱动ddt
  20. C语言学习纯纯小白-1,C语言代码开头为什么要有#include <stdio.h>

热门文章

  1. 计算机毕业设计-基于Java的GUI实现贪吃蛇小游戏
  2. 单片机综合实验 - 06 | 数字温度计设计
  3. 各种media格式说明
  4. 英伟达公布新的AI系统:可以凭空创造人物肖像 | 业内
  5. 【XCP学习笔记】1 XCP协议初步
  6. 新鲜出炉的精美2012年9月桌面日历壁纸免费下载
  7. 【音视频开发】为什么无损音频会有44.1Khz这样的奇葩采样率?
  8. 中国信通院推出了一个“APP签名服务系统,可防篡改、可追溯、第三方认证“的初步了解
  9. 【RAC】 RAC For W2K8R2 安装--grid的安装(四)
  10. Ubuntu使用OpenMVG和OpenMVS进行三维重建