MySQL磁盘是如何存储一行数据的?

举报
JavaEdge 发表于 2022/02/06 20:02:01 2022/02/06
【摘要】 MySQL物理数据模型每一行数据都是放在数据页,按数据页为单位把磁盘上的数据加载到内存的缓存页里来,也是按照页为单位,把缓存页的数据刷入磁盘上的数据页中。表、行和字段是逻辑上的概念,而表空间、数据区和数据页就是物理概念。表空间、数据页这些东西,都对应到了MySQL在磁盘上的一些物理文件。SQL语句仅指定查询或更新哪个表的哪些数据,怎么知道:这些数据在哪个表空间?哪个数据区?哪些数据页?对应...

1 MySQL物理数据模型

每一行数据都是放在数据页,按数据页为单位把磁盘上的数据加载到内存的缓存页。也是以页为单位,将缓存页的数据刷入磁盘上的数据页。

  • 表、行和字段是逻辑上的概念
  • 表空间、数据区和数据页是物理概念。这些东西对应到MySQL在磁盘上的一些物理文件。

SQL语句仅指定查询或更新哪个表的哪些数据,那它是怎么知道:

  • 这些数据在哪个表空间?哪个数据区?哪些数据页?对应MySQL节点的哪些磁盘文件?

2 为何不直接更新磁盘数据?

来个请求就直接对磁盘文件进行随机读写,然后更新磁盘文件里的数据,执行请求性能必然极差。因为磁盘随机读写性能极差,所以MySQL才设计了这套机制,通过在内存里更新数据,然后写redo log及事务提交,后台线程不定时地刷新内存数据到磁盘文件。

这样每个更新请求,基本都是更新内存,然后顺序写日志文件,这两种操作性能都是很高的。

3 数据页的意义

执行update之类的SQL时,必然涉及数据更新,此时对数据不是直接更新磁盘文件,而是要把磁盘上的一些数据加载到内存,然后对内存里的数据进行更新,同时写redo log到磁盘。

难道每次都是把磁盘里的一条数据加载到内存里去更新,然后下次要更新别的数据时,再从磁盘里加载另外一条数据到内存?这样每次一条条数据加载到内存里更新,效率太低!

为此,InnoDB引入数据页:将数据组织成一页页的,每页16K,然后每次加载磁盘数据到内存时,至少加载一页甚至多页的数据:

假设执行:

update xxx set xxx=xxx where id=1

则此时会将id=1这条数据所在的一页数据都加载到内存,这页的数据里可能还包含id=2,id=3的数据。

更新完id=1的数据后,接着更新id=2的数据,那此时就不用再读磁盘里的数据了,因为id=2本就和id=1同页,之前这页数据就已被加载到内存,所以此时,直接更新内存里的数据页中的id=2这条数据即可。

磁盘和内存间的数据交换通过数据页来执行,包括内存里更新后的脏数据,刷回磁盘时,也是至少一个数据页刷回去。

因此,我们就能一直在内存里更新各种数据,当I/O线程把内存里的脏数据刷到磁盘时,也是以数据页为单位刷回。

4 MySQL磁盘如何存储一行数据?

对一个表,可指定其行存储的格式,比如这里用COMPACT格式:

CREATE TABLE table_name (columns) ROW_FORMAT=COMPACT

ALTER TABLE table_name ROW_FORMAT=COMPACT

建表时,就可指定行存储格式,后续也能修改。

COMPACT行存储格式下,每行数据实际存储时,格式如下:

变长字段的长度列表,null值列表,数据头,column01的值,column02的值,column0n的值......

对于每行数据,存储时都会有一些头字段对这行数据进行描述,再放上这一行数据每一列具体值,这就是所谓的行格式。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。