普通索引和唯一索引详解

前言

面试的时候有时会问面试者,普通索引和唯一索引有什么区别。很多人,甚至工作很多年的工程师回答的千篇一律 “普通索引可以有重复的值,唯一索引不能有重复的值”。于是我又问,这两个索引这两个索引效率哪个高,很少有人回答的很好。下面我会从查询和更新多个维度去剖析这两个索引的区别。

现在我们系统有这样一个需求,根据用户的身份证查询用户的信息,用户表的数据很多。

select name from user where id_card='xxxx003'

为了查询的高效,我们肯定是要为id_card 建立索引,应该建立什么索引呢,有人说是主键索引,主键索引当然不合适,有下面几个原因:

  1. id_card 不能保证顺序递增,可能会导致页的分裂,

  2. 还有所占字节太大,主键索引每个叶存的数据太少,其他索引所占的空间也会增多,影响这个数据库的性能。

主键索引不合适,那么就剩下普通索引和唯一索引,对于这个需求,我们将逐步展开讨论。下面我将画出innodb 索引组织结构

接下来,我们就从这两种索引对查询语句和更新语句的性能影响来进行分析。

查询的区别

这个语句在B+tree 中查询过程是这样的,我们从id_card 索引树根开始查找,按层搜索到叶子节点,也就是找到了图中又下脚的那个数据叶。然后可以为数据页 内部通过二分法来定位记录。

  1. 那么对于普通索引来说,查找到 (xxxx003,3) 还需要往下找,直到找到下一个 id_card !='xxxx003' 停止

  2. 对于唯一索引来说,查找到 (xxxx003,3) 就停止,因为索引是唯一性的,查找到第一个满足条件的记录后,就会停止继续检索。

为此很多人感觉唯一索引在查询性能上高于普通索引,这个对性能的消耗微乎其微的。为什么呢?

在这里给大家解释下:

大家都知道,在innodb 查询数据的时候,都是按数据页为单位读取的,也就是说,当我们查询一条数据,并不是这个记录本身从磁盘读出来,而是把这条数据所在页从磁盘中读出来,叶的默认大小是16kB,接下来的查询一般来说会在内存中遍历。为什么说一般来说呢,如果这条记录是页的最后一条,会经过磁盘对数据,稍微复杂点,这种概率很低,可以忽略。

更新的区别

Innodb 有个WAL机制,所谓的WAL机制就是先写日志,在刷盘。这样可以提高数据库的性能,否则只有每次读盘,特别是机械磁盘,一次读盘需要经过寻道,旋转,传输,性能会受到很大的影响。

对于日志来说不得不提到redo log 以及 change buffer,简单对比这两个机制在更新性能上的收益来说,redo log 主要节省的是随机写磁盘的 IO 消耗(转成顺序写),而 change buffer 主要节省的则是随机读磁盘的 IO 消耗。

change buffer 的WAL机制是怎么实现的?

当需要更新一个数据页的时候,如果数据页在内存中直接更新,没有在内存中,在不影响数据一致性的前提下,innodb 会将这个更新操作缓存到change buffer中,这样就不用从磁盘读取这个数据页了。下次查询这个数据页,在将数据页读到内存中,执行change buffer 与这个数据页有关的操作。这种方式就能保证这个数据逻辑的正确性。说明的是change buffer 不仅在内存中有,也会被写到磁盘中。

上面我们说到执行change buffer 与这个数据页有关的操作,就是我们所说的merge。以下情况也会出发merge,数据库正常关闭,后台线程会定时merge。

是不是很神奇,那么是不是只要对数据库的更新都能用到change buffer,其实不一定的。

现在举一个例子,我们要插入(5,xxxx005) 这条记录,我们要分情况讨论。

第一种情况,这个记录要更新的目标页在内存中。两种索引处理流程是这样的

  1. 唯一索引,会看 xxxx004 和 下一条记录之间是否存在一条 xxxx005的记录,没有才插入,语句执行结束。

  2. 普通索引,会在 xxxx004 和 下一条记录之间直接插入一条xxxx005的记录,语句执行结束。

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

第二种情况,这个记录要更新的目标页不在内存中

  1. 唯一索引,需要将数据页读入内存中,判断到没有冲突,插入这个值,语句执行结束

  2. 普通索引,只需要该记录在change buffer ,语句就执行结束了

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

唯一索引哪种情况下都无法使用change buffer,而普通索引可以通过使用change buffer通过减少磁盘的随机读而提高性能。在想想,如果数据在更新后,立马就读取。是不是每次都要触发change buffer 的merge ,不仅要随机读还要维护chage buffer。

那么普通索引和唯一索引该怎么选择了?

我们在业务开发时第一原则是保证业务的准确性,确实需要唯一索引保证数据的唯一性,我们用唯一索引。除此之外,普通索引的优点还是很多的,特别是有些业务写多,读少比如历史数据,特别是数据量很大的情况收益还是非常显著的。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2821890.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

ant design pro的react项目build之后页面为空白解决方法

一、问题 执行yarn build之后访问dist文件夹中的index.html文件为空白 二、解决方法 找到config文件夹中的config.ts文件 添加代码 history: {type: hash }, publicPath: ./,修改完重新build一下就好了

BY组态功能清单

演示地址 :http://www.byzt.net:60/sm/ 官网地址:http://www.hcy-soft.com BY组态是一款非常优秀的纯前端的【web组态插件工具】,可无缝嵌入到vue项目,react项目等,由于是原生js开发,对于前端的集成没有框架…

你真的了解C语言中的【柔性数组】吗~

柔性数组 1. 什么是柔性数组2. 柔性数组的特点3. 柔性数组的使用4. 柔性数组的优势 1. 什么是柔性数组 也许你从来没有听说过柔性数组这个概念,但是它确实是存在的。 C99中,结构体中的最后⼀个元素允许是未知大小的数组,这就叫做柔性数组成员…

Spring Boot整合Kafka

文章目录 1. 介绍2. Kafka基础2.1. 安装KafKakafka集群搭建_kafka交流群-CSDN博客 3. Spring Boot整合Kafka3.1. 引入Kafka依赖3.2.编写配置文件 4. 生产者(produced)4.1. 生产者基础案例(基础测试) 5. 消费者5.1.消费者基本案例(基础测试) 6.Kafka常用配…

python 公共函数及操作符使用示例合集

python公共操作符以及方法是什么 在Python中,公共操作通常指的是那些可以对不同数据类型(如数字、字符串、列表、元组、字典等)进行操作的通用函数或方法。这些操作符或函数通常是内置的,并且可以在Python的官方文档中找到。 主要…

数字电路 第五章—第四节(顺序脉冲发生器)

一、计数型顺序脉冲发生器 1、电路组成 计数型顺序脉冲发生器一般都是按自然态序计数的二进制计数器和译码器组成。 2、输出4个脉冲的顺序脉冲发生器 (1)逻辑电路图(采用JK触发器): (2)时序图…

二叉搜索树的范围和(Lc938)——DFS

给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和。 示例 1: 输入:root [10,5,15,3,7,null,18], low 7, high 15 输出:32示例 2: 输入:root [10,5,15,3,7,13,18,1,nul…

家居清洁必备:2024如何挑选高效家用洗地机的实用指南

对于养宠物的家庭来说,宠物的毛发无处不在,尤其在换毛季节,清理工作更加繁琐。此时,洗地机的出现为解决这些问题提供了便利。洗地机可以同时扫地和拖地,实现高效清洁,减轻了清洁负担。而且,洗地…

【爬虫逆向实战 逆向滑块 Python+Node】今天逆向的网站有点嘿嘿,还是仅供学习,别瞎搞

逆向日期:2024.03.01 使用工具:Node.js、Python 加密方法:AES标准算法 文章全程已做去敏处理!!! 【需要做的可联系我】 AES解密处理(直接解密即可)(crypto-js.js 标准算…

windows系统安装《植物大战僵尸2009原版》教程

本文演示如何在windows免费安装 植物大战僵尸2009原版。 首先到 点此下载安装包 此页面最末端下载百度网盘分享的安装包。 下载完成后安装如下步骤进行安装: 安装完成即可开心的玩耍啦! 我自己的安装过程录屏在这里 https://www.bilibili.com/vid…

新 Logo 正式发布,Tubi 品牌全面升级!

作为新一代观众的首选流媒体平台,Tubi 持续扩大自身影响力,并于近日推出了富有活力的新品牌形象。 根据 Nielsen 的 The Gauge 报告,Tubi 在 2024 年 1 月的电视总观看份额提升至 1.5%,在年轻人和多元化观众群体中的吸引力持续上升…

MYSQL--JDBC优化

一.JDBC优化: 优化前提: 有时候我们并不清楚某些表当中一共有多少列,以及这些列的数据类型,这个时候我们就需要提前通过一些方法提前了解到这些数据,从而更好的进行输出 具体语句: package cn.jdbc;import java.sql.*;public class JDBCDEmo1 {public static void main(String…

11.盛最多水的容器

题目:给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 解题思路:可以…

2023 re:Invent AI 生成产品体验,从 Bedrock 到 Amazon Q

引 如果你也有如下问题,那么接下来的文字会一一为你解答 一套数据集,如何微调不同类型的开源大模型?—— Bedrock 如何只有产品说明书,如何构建一个智能问答机器人?—— Q 哪里还有免费的 GPU 算力——在线 Jupyter…

JQMobile Loader Widget 遮罩层改造

最近在用jqmobile 做一个混合APP项目时候用到 jqmobile1.4.3提供的Loader Widget控件,但是这个控件本身是一个loading弹出层,这个弹出层弹出之后,用户还是可以去点击按钮,重复发送请求,为了防止重复提交,我想了两种办法, 1,在loading弹出层弹出之后,让按钮不可用.但是form表单…

DC28V270V转AC36V115V航空逆变器

在当今的航空航天电源行业中,DC28V270V转AC36V115V航空逆变器发挥着至关重要的作用。作为一种关键的逆变器电源设备,DC28V270V转AC36V115V航空逆变器不仅在航空领域有着广泛的应用,还在许多其他领域发挥着重要作用。 一、DC28V270V转AC36V11…

源码的角度分析Vue2数据双向绑定原理

什么是双向绑定 我们先从单向绑定切入,其实单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新。那么双向绑定就可以从此联想到,即在单向绑定的基础上,用户更新…

GoFrame:如何简单地搭建一个简单地微服务

一切资料来源于GoFrame官网, 感兴趣的, 可以直接去官网查阅相关资料。 首先下载框架工具, 下载地址:https://github.com/gogf/gf/releases 然后进入你想要放置的项目文件夹, 执行命令行 gf init {project_name} #project_name为你的项目名 执行完后项目结构如图所示 然…

Java ElasticSearch-Linux面试题

Java ElasticSearch-Linux面试题 前言1、守护线程的作用?2、链路追踪Skywalking用过吗?3、你对G1收集器了解吗?4、你们项目用的什么垃圾收集器?5、内存溢出和内存泄露的区别?6、什么是Spring Cloud Bus?7、…

Java构造方法总结(很清晰)

构造方法扫盲:构造方法就是为了创建对象的 解释:真正创建对象的是 new 这个关键字,Java 虚拟机在创建对象时是有很多步骤的,构造方法只是其中的一步,它的作用是进行成员变量初始化。