引言

我们都知道,mysql中的索引,事务,锁等都是作为开发人员要重点掌握的知识面,但要想掌握理解好这些知识却并非易事。

其中原因之一就是这些概念都过于抽象,事实上如果都不懂mysql数据是以一种怎样结构存储的,就直接去学习索引等模块,如此理解起来自然是事倍功半的。

因此本文的目的有两点:

  • 揭露数据存储的格式
  • 说明Mysql是如何读取数据

在正文开始之前要先明确一点,Mysql有很多存储引擎,不同的存储引擎对于数据的存放格式是不一样的,目前Mysql的存储引擎默认是InnoDB,因此本文主要以InnoDB的角度去讲解。

行格式

我们经常会说往表中插入一条数据,实际上InnoDB数据存储的基本单位其实就是一条数据。这行数据在磁盘上存储的格式就叫做行格式。

InnoDB设计了4种行格式,分别是Compact、Redundant、Dynamic和Compressed行格式,接下来我们会重点讲解Compact,同时它也是最常用的行格式。

COMPACT行格式

直接先看一张图:

看图说话,Compact行格式可以分为两大块:

  • 额外信息
  • 真实数据

所谓真实数据自然就是我们要存放的值,而额外信息存储的是对这行记录的一些描述。

其中额外信息包括变长字段长度列表,NULL值列表,记录头信息。

变长字段长度列表

在Mysql有一些数据类型,比如VARCHAR(M)、TEXT等,它们是属于支持变长的数据类型,实际使用的字节数是不固定的。所以Mysql需要把这些类型的列实际使用了多少字节数给记录下来,记录的地方就是在变长字段长度列表

在Compact行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放。

举个例子,我们创建个表

CREATE TABLE record_format_demo (
-> c1 VARCHAR(10),
-> c2 VARCHAR(10) NOT NULL,
-> c3 CHAR(10),
-> c4 VARCHAR(10)
-> )

可以看到c1,c2,c4列都是变长的,此时我们插入一条数据

INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', 'cc', 'd')

我们假定内容占用的字节为

列名 存储内容 占用字节(十六进制表示)
c1 'aaaa' 0x04
c2 'bbb' 0x03
c4 'd' 0x01

所以这条记录的存储格式就为

可以看到变长字段长度列表是逆序(c4->c2->c1)排放的。

因此要计算1个变长字段到底占用了多少空间要计算两部分:

  • 真实数据占用的空间
  • 记录真实数据占用空间所使用的字节数

以列C1为例:

占用字节数='aaaa'(4字节)+ '0x04'(1字节)

NULL值列表

我们知道表中的某些列可能存储NULL值,如果把这些NULL值都放到记录的真实数据中存储会很占地方,所以Compact行格式把这些值为NULL的列统一管理起来,存储到NULL值列表中。

每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排列,,二进制位表示的意义如下:

  • 二进制位的值为1时,代表该列的值为NULL。
  • 二进制位的值为0时,代表该列的值不为NULL。

我们在来插入一条记录

INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', null, null)

因此这条记录的null值列表就是:

行格式就是:

可以看到二进制110就是十进制的6.

记录头信息

记录头信息,它是由固定的5个字节组成。5个字节也就是40个二进制位,不同的位代表不同的意思。本文不会细讲,在后续的文章中有涉及再说讲解。

真实数据

真实数据除了c1、c2、c3、c4这几个我们自己定义的列的数据以外,其实MySQL会为每个记录默认的添加一些列(也称为隐藏列),具体的列如下:

transaction_id和roll_pointer的作用将会在后面提及。

而row_id这个列只有在表没有自定义主键并且Unique键的情况下才会添加,作为表的主键。

以上就是InnoDb存储数据的行格式,下一篇文章将会介绍页的概念。

Mysql综述(1)数据是如何读存的的更多相关文章

  1. Mysql综述--数据是如何读存的?(2)

    页的结构 页是一种InnoDB管理存储空间的基本单位,它一般大小在16kb左右.实际上存在着许多不同类型的页,我们这次主要介绍的页是用来存储数据的,也叫做索引页. 接下来看看索引页的结构图: 比较重要 ...

  2. CentOS6 更改Mysql数据库的数据存放位置

    mysql使用yum安装时,默认的数据是存储在/var/lib/mysql下.一般情况下,为了数据的安全性,建议将mysql数据库的数据文件存储在系统的第二块磁盘上的目录下可以按照以下步骤进行操作: ...

  3. php查询mysql返回大量数据结果集导致内存溢出的解决方法

    web开发中如果遇到php查询mysql返回大量数据导致内存溢出.或者内存不够用的情况那就需要看下MySQL C API的关联,那么究竟是什么导致php查询mysql返回大量数据时内存不够用情况? 答 ...

  4. 大数据学习day33----spark13-----1.两种方式管理偏移量并将偏移量写入redis 2. MySQL事务的测试 3.利用MySQL事务实现数据统计的ExactlyOnce(sql语句中出现相同key时如何进行累加(此处时出现相同的单词))4 将数据写入kafka

    1.两种方式管理偏移量并将偏移量写入redis (1)第一种:rdd的形式 一般是使用这种直连的方式,但其缺点是没法调用一些更加高级的api,如窗口操作.如果想更加精确的控制偏移量,就使用这种方式 代 ...

  5. [转] MySql 优化 大数据优化

    一.我们可以且应该优化什么? 硬件 操作系统/软件库 SQL服务器(设置和查询) 应用编程接口(API) 应用程序 ------------------------------------------ ...

  6. 快速的mysql导入导出数据(load data和outfile)

    1.load data: ***实际应用:把日志生成的xls文件load到MySQL中: mysql_cmd = "iconv -c -f utf-8 -t gbk ./data/al_ve ...

  7. redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)

    一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...

  8. Ubuntu系统下MySQL读取文件数据ERROR解决

    博文链接:http://haoyuanliu.github.io/2016/04/29/mysql/ 对,我是来骗访问量的!O(∩_∩)O~~ 在使用MySQL进行文件数据读取的时候,在终端敲入命令行 ...

  9. 用python批量向数据库(MySQL)中导入数据

    用python批量向数据库(MySQL)中导入数据 现有数十万条数据,如下的经过打乱处理过的数据进行导入 数据库内部的表格的数据格式如下与下面的表格结构相同 Current database: pyt ...

随机推荐

  1. HBase 官方文档0.90.4

    HBase 官方文档0.90.4 Copyright © 2010 Apache Software Foundation, 盛大游戏-数据仓库团队-颜开(译) Revision History Rev ...

  2. 神奇的 SQL 之谓词 → 难理解的 EXISTS

    前言 开心一刻 我要飞的更高,飞的更高,啊! 谓词 SQL 中的谓词指的是:返回值是逻辑值的函数.我们知道函数的返回值有可能是数字.字符串或者日期等等,但谓词的返回值全部是逻辑值(TRUE/FALSE ...

  3. 06.Django基础五之django模型层(二)多表操作

    一 创建模型 表和表之间的关系 一对一.多对一.多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束. ...

  4. mybatis无法给带有下划线属性赋值问题

    https://blog.csdn.net/qq_33768099/article/details/69569561

  5. JavaScript DOM 编程艺术

    最近把JavaScript DOM 编程艺术这本书看完了,觉得这本书很好 深入浅出地展示了渐进增强.平稳退化.结构和样式分离等编程思想,我对书中重要的知识进行了梳理总结. 一.网页 二.JavaScr ...

  6. Python学习-迭代器、生成器

    一.迭代器 1. 可迭代对象 我们知道字符串.列表.元组.字典.集合都可以使用for语句进行循环遍历,然后输出每一个元素,这些都是可迭代对象. 检查对象是否是可迭代对象可以用两种方式去判断: (1)使 ...

  7. linux添加默认网关

    运维常用linux命令整理 1.临时添加 route add default gw 192.168.1.4 2.永久添加 vim /etc/sysconfig/network GATEWAY=192. ...

  8. 蓝桥杯 algo122 未名湖的烦恼 简单题

    #include <iostream> using namespace std; int m, n, ans; void solve(int m, int n, int cnt) { &a ...

  9. VMbox 安装 LInux系统流程

    STEP 1 文件--新建---(自定义高级)---(默认设置)---(稍后安装系统)---(Linux+选择版本)---(虚拟机名字+存放位置)---(处理器2+核数2)---(虚拟机内存)2G一般 ...

  10. 一个selenium简单案例自动添加数据

    //本来想着用execl来录入数据的,但是为了尽快完成所以直接搞了个数组 package aldtest; import org.openqa.selenium.*; import org.openq ...