mysql 学习 - InnoDB的行

InnoDB行

我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。InnoDB存储引擎到现在为止设计了4种不同类型的行格式,分别是Compact、Redundant、Dynamic和Compressed行格式

compact(行格式)

记录的额外信息这部分信息是服务器为了描述这条记录而不得不额外添加的一些信息,这些额外信息分为3类,分别是变长字段长度列表、NULL值列表和记录头信息



关于变长字段

变长的数据类型,比如VARCHAR(M)、VARBINARY(M)、各种TEXT类型,各种BLOB类型,我们也可以把拥有这些数据类型的列称为变长字段,变长字段中存储多少字节的数据是不固定的,这种字段叫做变长字段.

对于变长字段, 除了存储真实值外, 还需要将真实值的长度使用变长字段长度列记录

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

变长字段长度列表中只存储值为 非NULL 的列内容占用的长度,值为 NULL 的列的长度是不储存的

并不是所有记录都有这个 变长字段长度列表 部分,比方说表中所有的列都不是变长的数据类型的话,这一部分就不需要有。



关于NULL值列表

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

主键列、被NOT NULL修饰的列都是不可以存储NULL值的,所以在统计的时候不会把这些列算进去

如果表中没有允许存储 NULL 的列,则 NULL值列表 也不存在了

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

MySQL规定NULL值列表必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节,则在字节的高位补0. (一个字节=8位)

以此类推,如果一个表中有9个允许为NULL,那这个记录的NULL值列表部分就需要2个字节来表示了。



关于记录头信息

它是由固定的5个字节组成。5个字节也就是40个二进制位,不同的位代表不同的意思





隐藏列

除了上述的信息外, innnodb还为每条记录添加了隐藏列, 分别是: row_id(行id), transaction_id(事务id), roll_pointer(回滚指针)

InnoDB表对主键的生成策略:优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个Unique键作为主键,如果表中连Unique键都没有定义的话,则InnoDB会为表默认添加一个名为row_id的隐藏列作为主键。所以我们从上表中可以看出:InnoDB存储引擎会为每条记录都添加 transaction_id 和 roll_pointer 这两个列,但是 row_id 是可选的(在没有自定义主键以及Unique键的情况下才会添加该列)。这些隐藏列的值不用我们操心,InnoDB存储引擎会自己帮我们生成的。



char(M) 与 varchar(M)

这两个类型的列, 在界定是否为可变长度的列是, 主要取决于列使用的字符集是否是定长的, 比如 ascII字符集是定长为1字节(8位), 而utf8是不定长的, 一个字符要占用1-3字节. char(10) 类型的列要占用的字节为 10-30字节.

varchar(M)中M的最大值也要取决于列的字符集类型, 正常如果是 ascII字符集, 一个字符=1字节时, 最大长度也不能为 65535, 因为还需要给出标识是否为null等等信息的空间. 所以根据字符集的定长, 可以计算出M的最大值.

记录中的数据太多产生的行溢出

有如下所示数据库脚本语句:

mysql> CREATE TABLE varchar_size_demo(
    ->       c VARCHAR(65532)
    -> ) CHARSET=ascii ROW_FORMAT=Compact;
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO varchar_size_demo(c) VALUES(REPEAT(‘a‘, 65532));
Query OK, 1 row affected (0.00 sec)

MySQL中磁盘和内存交互的基本单位是页,也就是说MySQL是以页为基本单位来管理存储空间的,我们的记录都会被分配到某个页中存储。而一个页的大小一般是16KB,也就是16384字节,而一个VARCHAR(M)类型的列就最多可以存储65532个字节,这样就可能造成一个页存放不了一条记录的尴尬情况。

在Compact和Redundant行格式中,对于占用存储空间非常大的列,在记录的真实数据处只会存储该列的一部分数据,把剩余的数据分散存储在几个其他的页中,然后记录的真实数据处用20个字节存储指向这些页的地址(当然这20个字节中还包括这些分散在其他页面中的数据的占用的字节数),从而可以找到剩余数据所在的页,如图所示:


从图中可以看出来,对于Compact和Redundant行格式来说,如果某一列中的数据非常多的话,在本记录的真实数据处只会存储该列的前768个字节的数据和一个指向其他页的地址,然后把剩下的数据存放到其他页中,这个过程也叫做行溢出,存储超出768字节的那些页面也被称为溢出页, 不只是 VARCHAR(M) 类型的列,其他的 TEXT、BLOB 类型的列在存储数据非常多的时候也会发生行溢出, 所以你不用关注这个临界点是什么,只要知道如果我们一条记录的某个列中存储的数据占用的字节数非常多时,该列就可能成为溢出列.

Dynamic和Compressed行格式

为什么要介绍行溢出, 是因为要引出 Dynamic 和 Compress 行格式

它们不会在记录的真实数据处存储字段真实数据的前768个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址,就像这样:


Compressed 行格式和 Dynamic 不同的一点是,Compressed 行格式会采用压缩算法对页面进行压缩,以节省空间.


MySQL5.7,它的默认行格式就是 Dynamic

原文地址:https://www.cnblogs.com/it-dennis/p/12607883.html

时间: 2024-10-11 16:12:59

mysql 学习 - InnoDB的行的相关文章

Mysql学习——InnoDB与Myisam

MysqlInnoDB和Myisam两种类型的存储我们在Mysql创建表的时候可以在选项中进行制定,如下图所示: 下面来说说两种存储的区别吧: 1.两种数据存储的事务机制不同 InnoDB支持事务,Myisam不支持,但是在查询方面Myisam的性能略胜一筹 2.锁的机制不同 InnoDB为行级锁,能更大程度的支持并发操作:Myisam是表级锁 3.数据操作方面 修改.新增.删除数据使用InnoDB性能更高,大数据量的查询使用Myisam性能更高 查询数据库条数时InnoDB不保存表中数据的条数

MySQL学习之——锁(行锁、表锁、页锁、乐观锁、悲观锁等)

锁,在现实生活中是为我们想要隐藏于外界所使用的一种工具.在计算机中,是协调多个进程或县城并发访问某一资源的一种机制.在数据库当中,除了传统的计算资源(CPU.RAM.I/O等等)的争用之外,数据也是一种供许多用户共享访问的资源.如何保证数据并发访问的一致性.有效性,是所有数据库必须解决的一个问题,锁的冲突也是影响数据库并发访问性能的一个重要因素.从这一角度来说,锁对于数据库而言就显得尤为重要. MySQL锁 相对于其他的数据库而言,MySQL的锁机制比较简单,最显著的特点就是不同的存储引擎支持不

mysql 学习 - InnoDB的页

页 InnoDB是一个将表中的数据存储到磁盘上的存储引擎,所以即使关机后重启我们的数据还是存在的.而真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上. 不论是读取数据还是写入数据, InnoDB 引擎是以页为单位操作的. 将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小一般为 16 KB.也就是在一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB

重新学习MySQL数据库2:『浅入浅出』MySQL 和 InnoDB

重新学习Mysql数据库2:『浅入浅出』MySQL 和 InnoDB 作为一名开发人员,在日常的工作中会难以避免地接触到数据库,无论是基于文件的 sqlite 还是工程上使用非常广泛的 MySQL.PostgreSQL,但是一直以来也没有对数据库有一个非常清晰并且成体系的认知,所以最近两个月的时间看了几本数据库相关的书籍并且阅读了 MySQL 的官方文档,希望对各位了解数据库的.不了解数据库的有所帮助. 本文中对于数据库的介绍以及研究都是在 MySQL 上进行的,如果涉及到了其他数据库的内容或者

mysql中InnoDB存储引擎的行锁和表锁

Mysql的InnoDB存储引擎支持事务,默认是行锁.因为这个特性,所以数据库支持高并发,但是如果InnoDB更新数据的时候不是行锁,而是表锁的话,那么其并发性会大打折扣,而且也可能导致你的程序出错. 而导致行锁变为表锁的情况之一就是: SQL的更新(update)或者删除(delete)语句中未使用到索引,导致在InnoDB在对数据进行相应操作的时候必须把整个表锁起来进行检索(表锁).而如果使用了索引的话,InnoDB只会通过索引条件检索数据,而只锁住索引对应的行(行锁). 下面记录一下我遇到

一千行MySQL学习笔记

/* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限验证登录MySQL */ mysqld --skip-grant-tables -- 修改root密码 密码加密函数password() update mysql.user set password=password('root'); SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES --

一千行MySQL学习笔记(七)

/* 事务(transaction) */ ------------ 事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败. - 支持连续SQL的集体成功或集体撤销. - 事务是数据库在数据晚自习方面的一个功能. - 需要利用 InnoDB 或 BDB 存储引擎,对自动提交的特性支持完成. - InnoDB被称为事务安全型引擎. -- 事务开启 START TRANSACTION; 或者 BEGIN; 开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句. -- 事

mysql: 关于MySQL InnoDB锁行还是锁表?

baidu zone - 关于MYSQL Innodb 锁行还是锁表,深入讲解

一千行MySQL学习笔记【博客园】

/* 启动MySQL */ net start mysql /* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码 /* 跳过权限验证登录MySQL */ mysqld --skip-grant-tables -- 修改root密码 密码加密函数password() update mysql.user set password=password('root'); SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES --