Mysql综述(1)数据是如何读存的
引言
我们都知道,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)数据是如何读存的的更多相关文章
- Mysql综述--数据是如何读存的?(2)
页的结构 页是一种InnoDB管理存储空间的基本单位,它一般大小在16kb左右.实际上存在着许多不同类型的页,我们这次主要介绍的页是用来存储数据的,也叫做索引页. 接下来看看索引页的结构图: 比较重要 ...
- CentOS6 更改Mysql数据库的数据存放位置
mysql使用yum安装时,默认的数据是存储在/var/lib/mysql下.一般情况下,为了数据的安全性,建议将mysql数据库的数据文件存储在系统的第二块磁盘上的目录下可以按照以下步骤进行操作: ...
- php查询mysql返回大量数据结果集导致内存溢出的解决方法
web开发中如果遇到php查询mysql返回大量数据导致内存溢出.或者内存不够用的情况那就需要看下MySQL C API的关联,那么究竟是什么导致php查询mysql返回大量数据时内存不够用情况? 答 ...
- 大数据学习day33----spark13-----1.两种方式管理偏移量并将偏移量写入redis 2. MySQL事务的测试 3.利用MySQL事务实现数据统计的ExactlyOnce(sql语句中出现相同key时如何进行累加(此处时出现相同的单词))4 将数据写入kafka
1.两种方式管理偏移量并将偏移量写入redis (1)第一种:rdd的形式 一般是使用这种直连的方式,但其缺点是没法调用一些更加高级的api,如窗口操作.如果想更加精确的控制偏移量,就使用这种方式 代 ...
- [转] MySql 优化 大数据优化
一.我们可以且应该优化什么? 硬件 操作系统/软件库 SQL服务器(设置和查询) 应用编程接口(API) 应用程序 ------------------------------------------ ...
- 快速的mysql导入导出数据(load data和outfile)
1.load data: ***实际应用:把日志生成的xls文件load到MySQL中: mysql_cmd = "iconv -c -f utf-8 -t gbk ./data/al_ve ...
- redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)
一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...
- Ubuntu系统下MySQL读取文件数据ERROR解决
博文链接:http://haoyuanliu.github.io/2016/04/29/mysql/ 对,我是来骗访问量的!O(∩_∩)O~~ 在使用MySQL进行文件数据读取的时候,在终端敲入命令行 ...
- 用python批量向数据库(MySQL)中导入数据
用python批量向数据库(MySQL)中导入数据 现有数十万条数据,如下的经过打乱处理过的数据进行导入 数据库内部的表格的数据格式如下与下面的表格结构相同 Current database: pyt ...
随机推荐
- FreeSql (六)批量插入数据
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" + "Initia ...
- android 之下拉刷新
一.概述 Android 下拉刷新几乎是每个应用都必带的功能, 并且现在下拉刷新第三方库也越来越多了,很方便就能实现该功能, 下面我介绍一下 自己常用的几个方法. 二.例子 第一种方式:就是集成Lis ...
- tensorflow 使用 cpu 而不使用 gpu 问题
查看 tensorflow 版本 conda list 例如发现 tensorflow 1.10.0 tensorflow-gpu 1.10.0 当两个版本相同时,默认会使用 cpu 版本 如果同时存 ...
- Elastic Stack 笔记(五)Elasticsearch5.6 Mappings 映射
博客地址:http://www.moonxy.com 一.前言 关系型数据库对我们来说都很熟悉,Elasticsearch 也可以看成是一种数据库,所以我们经常将关系型数据库中的概念和 Elastic ...
- springboot之全局处理异常封装
springboot之全局处理异常封装 简介 在项目中经常出现系统异常的情况,比如NullPointerException等等.如果默认未处理的情况下,springboot会响应默认的错误提示,这样对 ...
- JsonConvert 转DateTime类型为json 带T
在调用接口的时候 将Model转换成json Datetime类型多了个T 用的是Newtonsoft.Json.dll 版本v4.5.0.0 代码:paramsjson = JsonConvert ...
- 如何基于String实现锁?
在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理.因为只有在相同字符串的情况下,并发操作才是不被允许的. 因为String 类型的变量赋值是 ...
- 【linux】linux固定ip
vi /etc/sysconfig/network-scripts/ifcfg-ens33 ifcfg-ens33为ifconfig显示的网卡名 TYPE="Ethernet"P ...
- setInterval、setTimeout之遗忘的第三个参数
今天看阮一峰老师的ES6入门,在一个关于promise的小demo里,老师用到了setTimeout的第三个参数,惊了有没有,定时器还有第三个参数? 喏就是下面这个demo: function tim ...
- CentOS 8 都发布了,你还不会用 nftables?
原文链接:CentOS 8 都发布了,你还不会用 nftables? 如果你没有生活在上个世纪,并且是云计算或相关领域的一名搬砖者,那你应该听说最近 CentOS 8 官方正式版已经发布了,CentO ...