为了搞清楚MySQL对于可变长度字段值修改时,如何高效操作数据文件的机制。之前一直模糊不清,网上也搜不到现成的答案。经过多方资料搜集整理。写出此文供大家一起参阅。由于涉及众多非常底层的知识,我假设读者已经对操作系统和磁盘存取有一定的基础知识。文中如有疏漏,还请大佬指正。
  为了探究这个问题,我们要先来回顾一下我之前的一篇文章《文件随机或顺序读写原理深入浅出》讲的文件存储的底层原理知识。如下图所示。一个文件的数据是以块为单位存储到物理磁盘的随机位置,这是由操作系统负责管理的,用户程序无权决定。所以在文件视图层面我们连续存储的数据,映射到物理磁盘层面就是随机位置了。图中是假设磁盘块大小为32KB,则文件对应的数据偏移地址存储到对应的物理块中示意图。
  我们现在假设MySQL的一张表对应一个数据文件。那么表里的数据按行存储,则行与行之间的数据被紧密的连续填充到上图“数据文件视图”中,并被以块为单位随机存储到了物理磁盘上。这样遍历表时,就可以从文件0地址开始依次读取到所有数据,行与行之间的间隔符就是普通的换行符。每一行中的字段都按照表结构定义中的字段长度读取即可。这里先假设表中的字段都是定长类型的。这样就不会有什么问题。即便是更新某个字段的值,则可以直接使用随机文件读取方法定位到字段的偏移地址写入新值即可覆盖旧值。
  那么现在问题来了,如果表中某字段是可变长类型的如varchar(50)。数据插入时假设值为“月光冷锋”,后面有个更新操作,需要将值改为“月光冷锋的博客”。此时会发生什么呢?由于是可变长度的字段类型,文件中该行的该字段实际占用空间就是四个字符,而不是50个字符。且行之间数据紧密排列存储。现在值要变成7个字符,则我们无法通过简单的随机文件存取定位到该字段覆盖旧值,这样会出现严重的问题,会覆盖其他字段或行的值。一种古老的文件修改方法是,先将要修改的位置后面的数据都转移到一个临时文件中,然后修改现在的位置处的值,最后再把临时文件的内容拼接回原文件,从而实现修改操作。显然这种方式无法应用到频繁更新的数据库上。这种方式代价巨大,不过大多数文件都是只读的,极少更新。所以应用也挺广泛的。比如音频、视频文件。
  那么MySQL是如何解决这类问题的呢?首先我们如果把表数据文件看成一个可以任意发挥的平台,我们不在像其他类型文件那样直接将数据一个挨着一个紧密的写入文件的偏移地址中。MySQL使用页这个概念重新对文件视图划分,也就是一个页对应一段文件的偏移地址。如下图所示。MySQL页大小默认16kB,刚好对应图中两个页对应到一个物理块32kb大小。MySQL的页使用双向链表方式组织。
  下面我们来看下如果可变长度varchar类型的字段值变长了,文件里的数据该怎么存储呢?因为表中数据刚开始插入时,可变长度字段值都是根据实际长度存储下来的,且行与行之间数据也是紧密连续存放在文件地址中的(再次强调一下,不是连续存放在物理磁盘上的)。那么现在值变长了,原来的位置无法扩展出新的空间出来,所以无法覆盖存放到原来的位置上。此时MySQL就会使用页分裂的方法扩展字段变长的空间。
  比如假设行10的数据存放在页③的位置,如下图2所示。行11也是存放在页③的位置,且他们两行都把页③填满了。现在更新行10的某个变长字段值,由“月光冷锋”改成“月光冷锋的博客”。MySQL将新创建一个页⑥出来(相应的原数据文件也要变大增长),把原来页③的内容,行10和行11的数据重新生成排列一遍存储到页③和页⑥中,同时将原来的页链表结构重新修改其前驱和后继页节点的指针就OK了。如下图3所示。
 图2         图3                                                                          
  MySQL就是通过这种技巧,实现了修改数据文件时,不必像传统修改文件那样付出昂贵代价。这种方式虽然解决了修改文件时避免大规模移动数据的弊端,但是读取这些数据时,却无法像传统存取方式那样,直接从文件偏移地址0开始顺序读取。而是要根据页的链表结构顺序读取。需要不断的计算和移动文件偏移量指针,好在这个过程不会花费多少代价。但是会带来另外一个比较严重的问题就是页空洞,也称为碎片。上面行11有部分字段数据已经转移到了页⑥中,显然页⑥是没有存满的。行12是存在页④中的,这样就产生了碎片问题,浪费了文件的一些地址空间,这些空洞存的都是特殊占位符,也要占据真实的物理磁盘空间。随着更新删除操作越来越多,碎片也会越来越多,所以有必要定期进行表的碎片整理,这样可以收缩表文件占据的磁盘空间。也可以降低页链表的长度,从而节省一些寻址操作代价。
  如果可变长字段值由大变小,则原来的字段值地址空间足够了,也就不需要新加页了,只需要重新整理排列一下当前更新的行数据即可。使得变成字段的值占用实际空间即可。至于留下的页碎片问题,MySQL也有相应的机制做合并优化操作。我这里不做深究。
 
 

mysql变成类型字段varchar值更新变长或变短底层文件存储原理的更多相关文章

  1. MySQL数据类型 int(M) 表示什么意思?详解mysql int类型的长度值问题

    MySQL 数据类型中的 integer types 有点奇怪.你可能会见到诸如:int(3).int(4).int(8) 之类的 int 数据类型.刚接触 MySQL 的时候,我还以为 int(3) ...

  2. EtherType :以太网类型字段及值

    Ethernet II即DIX 2.0:Xerox与DEC.Intel在1982年制定的以太网标准帧格式.Cisco名称为:ARPA Ethernet II类型以太网帧的最小长度为64字节(6+6+2 ...

  3. mysql int类型字段插入空字符串时自动转为0

    mysql int类型字段插入空字符串时自动转为0 如果不想转的话可以修改配置文件 修改 my.ini 文件. # Set the SQL mode to strictsql-mode=”STRICT ...

  4. 关于Java读取mysql中date类型字段默认值'0000-00-00'的问题

    今天在做项目过程中,查询一个表中数据时总碰到这个问题:      java.sql.SQLException:Value '0000-00-00' can not be represented as ...

  5. mysql列类型char,varchar,text,tinytext,mediumtext,longtext的比较与选择

    储存不区分大小写的字符数据 TINYTEXT 最大长度是 255 (2^8 – 1) 个字符. TEXT 最大长度是 65535 (2^16 – 1) 个字符. MEDIUMTEXT 最大长度是 16 ...

  6. Mysql各种类型字段长度

    1.数值类型 列类型 需要的存储量 TINYINT 1 字节 SMALLINT 2 个字节 MEDIUMINT 3 个字节 INT 4 个字节 INTEGER 4 个字节 BIGINT 8 个字节 F ...

  7. mysql 字符串类型 char varchar

    字符类型用在存储名字.邮箱地址.家庭住址等描述性数据   char指的是定长字符,varchar指的是变长字符 #官网:https://dev.mysql.com/doc/refman/5.7/en/ ...

  8. mysql int类型的长度值

    整数类型的存储和范围(来自mysql手册) 类型 字节 最小值 最大值     (带符号的/无符号的) (带符号的/无符号的) TINYINT 1 -128 127     0 255 SMALLIN ...

  9. 详解mysql int类型的长度值问题【转】

    mysql在建表的时候int类型后的长度代表什么? 是该列允许存储值的最大宽度吗? 为什么我设置成int(1), 也一样能存10,100,1000呢. 当时我虽然知道int(1),这个长度1并不代表允 ...

随机推荐

  1. 题解 [SHOI2012]随机树

    题目传送门 Description \(n\le 100\) Solution Problem 1 不难看出,答案就是: \[1+\sum_{i=1}^{n-1} 2/(i+1) \] Problem ...

  2. bzoj1972 SDOI2010-----猪国杀(模拟)

    题目自己去找吧 记得数据范围是<=10 注意事项: 1.牌库空的时候,要不断的抽第一张牌 2.反贼的决斗永远是向主公发的 3.每次判定无懈的时候,都是从使用锦囊的那个牌开始,记得敌意和殷勤的判断 ...

  3. 微软 SqlHelper代码、功能、用法介绍:高效的组件

    数据访问组件SqlHelper数据访问组件是一组通用的访问数据库的代码,在所有项目中都可以用,一般不需要修改.本节使用的是Microsoft提供的数据访问助手,其封装很严密,且应用简单. 首先要先添加 ...

  4. CompleteFuture实现简单的任务编排实践

    CompleteFuture实现简单的任务编排实践 一:前言 ​ CompleteFuture是java8 新提供的API,是对函数式编程思想的体现,提供了很多的对于函数式编程支持.不止有同步处理功能 ...

  5. Zookeeper+Dubbo环境搭建与Demo测试

     环境准备: 1. zookeeper-3.4.14     (下载地址:http://archive.apache.org/dist/zookeeper/) 2. dubbo-0.2.0 (下载地址 ...

  6. Prometheus的单机部署

    Prometheus的单机部署 一.什么是Prometheus 二.Prometheus的特性 三.支持的指标类型 1.Counter 计数器 2.Gauge 仪表盘 3.Histogram 直方图 ...

  7. 启动Dubbo项目注册Zookeeper时提示zookeeper not connected异常原理解析

    文/朱季谦 遇到一个很诡异的问题,我在启动多个配置相同zookeeper的Dubbo项目时,其他项目都是正常启动,唯独有一个项目在启动过程中,Dubbo注册zookeeper协议时,竟然出现了这样的异 ...

  8. 数位dp & 热身训练7

    数位dp 数位dp是一种计数用的dp,一般就是要统计一段区间$[L,R]$内,满足一定条件的数的个数,或者各个数位的个数. 数位dp使得暴力枚举变为满足一定状态的记忆化,更加优秀. 数位dp常常会考虑 ...

  9. error: unsupported reloc 43

    在Ubuntu 16.04.5 LTS编译android 5.1报错 [19:17:13.062]libnativehelper/JniInvocation.cpp:165: error: unsup ...

  10. 深入剖析Redis客户端Jedis的特性和原理

    一.开篇 Redis作为目前通用的缓存选型,因其高性能而倍受欢迎.Redis的2.x版本仅支持单机模式,从3.0版本开始引入集群模式. Redis的Java生态的客户端当中包含Jedis.Rediss ...