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 操作。

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

可以看到,先将更新操作记录在 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 不在。

c8dac20fe429846da26602ef8632bfb2.png

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

InnoDB buffer pool:内存区域

redo log:日志

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

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

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

执行过程如下:

k1 所在的 page1 在内存中,直接更新内存

k2 所在的 page2 不在内存中,记录在 change buffer.

将 k1 和 k2 的操作记录在 redo log.

提交事务。

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

再来看一条查询语句:

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

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

c313abead2145c9b40c5b859d616c0ee.png

执行过程:

读取 k1 所在的 page1,在内存中,直接返回。注意,并没有读磁盘上的数据,而且磁盘上的数据还有可能是之前的版本的。

读取 k2 所在的 page2,这时需要将 page2 从磁盘加载到内存,并应用 change buffer 的内容,然后返回正确的结果。从这里也能看出,change buffer 不适用于更新完立马去读的情况。

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

参考

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 反射 父类的属性_用反射的方式获取父类中的所有属性和方法

package com.syh.jdbc.reflection_super;/*** 父类* author syh**/public class Parent {public String publicField "1";String defaultField "2";protected String protectedField "3";private String privateField "4" ;public…

java中变量命名规范_关于java中变量命名规范的详细介绍

Java是一种区分字母的大小写的语言,所以我们在定义变量名的时候应该注意区分大小写的使用和一些规范,接下来我们简单的来讲讲Java语言中包、类、变量等的命名规范。(一)Package(包)的命名Package的名字应该都是由一个小写单词组成,例如com、x…

java找重复字符串_在java中怎样查找重复字符串

在一段java编程代码中,字符串是不可缺少的一个要素,属于java中的基础知识,字符串不仅在java面试题中会出现,在编写代码时更要掌握怎样使用字符串。在前面我们也学习过关于字符串截取的知识,你应该有所掌握吧、格式化字…

python excel 单元格格式_python设置单元格数值格式

python xlwt如何设置单元格格式python xlwt模块怎么设置excel单元格的属性如图,默认是general。我想写入的时候就是Text类型.请问应该怎么做。from xlwt import Workbook,Stylewb Workbook()ws wb.add_sheet(Type examples)ws.row(0).write(0,1)ws.row(0).set_cell_text(1,1)…

python调用.a静态库_Python 调用 C

了解了相关资料不折腾的方法有(以往文章有):pypy,numba,numpy但都不是 纯正的 C折腾的:cffi,Cython,Boost.Python,Cpython 自带模块,SWIG 等挺折腾的You can write an extension you…

java给一个数组随机数_Java案例-数组随机数

.数组案例分析定义一个int型的一维数组,包含10个元素,分别赋一些随机整数,然后求出所有元素的最大值Max,最小值Min,平均值Avg,和Sum值,并输出出来。具体实现代码:package teacher01;…

java 自旋方法_JAVA循环使用CAS实现自旋操作

大家碰到了实现一个线程安全的计数器的需求改怎么做呢?根据经验你应该知道我们要在多线程中实现共享变量的原子性和可见性问题,于是锁成为一个不可避免的话题,下文讨论的是与之对应的无锁CAS。为什么要无锁我们一想到在多线程下保证安全的方式…

java实现extended smtp_java实现发送邮件(SMTP)

1.pom引入包javax.mailmail1.4.72.Email实体类import lombok.Data;import lombok.EqualsAndHashCode;import lombok.experimental.Accessors;import java.util.List;import java.util.Map;/*** ClassName: Email* author: mxy* Description: Email的实体类*/DataEqualsAndHashC…

java addcallback函数_java中怎么使用callback函数?

UYOU在很多场景,作为开发都会想到,在执行完毕一个任务的时候,能执行一个callback函数是多么好的事情。现在模拟一下这个情景:定义三个类。分别是主函数类。callback函数的接口类。业务处理类。在业务处理类中,处理完业…

在java中的交换方法有哪些_java中交换两个变量的值有哪几种方法,交换两个变量a和b的值...

java中交换两个变量的值有哪几种方法在Java中,有哪些方法可以交换两个变量的值,方法:1.定义临时变量2.没有必要定义临时变量3.使用位运算符(学习视频分享:java课程)代码示例:公共类SwapTest {公共静态void main(String…

opc客户端读取数据品质是bad_听说看了这篇文章就彻底搞懂了什么是OPC(上)

从2000年初以来,我们就一直在使用OPC软件互操作性标准,而那些正准备踏入和想要踏入工业自动化领域的人们却对这些含义感到困惑。所以在本中,我将系统地为你梳理OPC知识。OPC首字母缩写词代表什么?问一个OPC老手,他们或…

php导入json文件_[php]导入超大json文件

前言在之前的文章《做一个twitter的插件玩玩》中,我做了一个批量删除推文(转发推文)的工具,该工具能够删除前3200条推文,但因为总数太多(4.3万条),api接口不支持获取所有的推文,所以我采用了下载的方式,直接…

linux怎样写java代码,linux 怎么写java

linux 怎么写java一、环境安装由于使用 yum 或者 apt-get 命令 安装 openjdk 可能存在类库不全,从而导致用户在安装后运行相关工具时可能报错的问题,所以此处我们推荐采用手动解压安装的方式来安装 JDK。具体步骤如下:1.下载 JDK进入Oracle官…

超级好用的一个php上传图片类(随机名_缩略图_加水印),超级好用的一个php上传图片类(随机名,缩略图,加水印)...

Upimages.class.php php上传类复制代码 代码如下:class UpImages {var $annexFolder "upload";//附件存放点,默认为:annexvar $smallFolder "small";//缩略图存放路径,注:必须是放在 $annexFolder下的子目录…

matlab读取data格式,ReadData3D 各种格式图像的读取,包括医学 效果很好 matlab 272万源代码下载- www.pudn.com...

文件名称: ReadData3D下载 收藏√ [5 4 3 2 1 ]开发工具: matlab文件大小: 51 KB上传时间: 2017-03-29下载次数: 0提 供 者: 李忠宽详细说明:各种格式图像的读取,包括医学图像的读取,效果很好-Various formats of image reading, inclu…

mysql vs2008,vs2008 使用mysql

近期转到研发岗,需要用到mysql、vs2008;之前由于没有做过,写下这篇文章记录下这周所学的东西!先安装好相关软件安装时间比较久耐心等待......安装完毕之后打开vs,Tools -> opptions ->设置完毕之后,点…

matlab pretty什么用,matlab如何使输出结果更美观(symdisp函数——pretty函数升级版)...

EDA365欢迎您登录!您需要 登录 才可以下载或查看,没有帐号?注册x& t7 n0 d: a# m0 O( y- Lmatlab中有些计算结果比较长,直接查看有些困难,下面介绍pretty和symdisp函数优化输出结果,使结果更为直观。- …

php 遮罩层,Jquery实现遮罩层的方法

本文实例讲述了Jquery实现遮罩层的方法。分享给大家供大家参考。具体如下:1、假设#main为页面body中的最外层Div标签2、背景被遮罩后,显示的弹出窗(默认是不显示的,所包含的CSS这里就不贴了):xAttention!3、在script.js中定义遮罩…

nhinx php 调优,高流量站点NGINX与PHP-fpm配置优化

本文由LinuxProbe.Com团队成员岳国帅整理发布,原文来自:黑白。导读使用Nginx搭配PHP已有7年的经历,这份经历让我们学会如何为高流量站点优化NGINX和PHP-fpm配置。以下正是这方面的一些提示和建议:1. 将TCP切换为UNIX域套接字1. 将…

php rinit,PHP执行原理

一:PHP简介:PHP:Hypertext Preprocessor 也就是“超文本预处理器”,是一种通用的开源脚本语言。语法吸收了C语言,Java和Perl的特点,使用广泛,主要适用于Web开发领域。二:PHP的设计理…