最近工作的时候突然想到一个关于大对象存储的问题。先看看这个问题的背景。
背景1:在mysql数据库(innodb引擎)中,我们有这样的业务场景,在一个表(下面我们称为tmp表)中有一个字段(我们称为describe字段)可能存储的内容会特别的大,假设describe字段的业务大小上限为64KB,使用TEXT类型来存储(文章最下方有字段参考)。
背景2:我们都知道innodb把所有的字段都存储在聚簇索引的叶子节点上,而在数据库的存储设计中,innodb的一个page(默认为16K)是希望能存储多个叶子节点,这样在读一个page页的时候能读到更多的叶子节点,减少查询的磁盘io。
那么问题来了:
那么tmp表中的describe字段大小都一静超过了16k了,一个page页已经存储不下了,innodb是怎么解决这个问题的呢?**
innodb是不是这么干的呢?
猜测1:是不是会扩展一个page的大小或者说把两个page页当做一个page页。
猜测2:会不会大字段就不放在叶子节点所在的页了,而是单独存储了。
好吧,下面就是通过查找资料来验证自己的猜测了。
问题探索
我们先来看一个概念。
数据行溢出: Innodb会将一条记录中的某些数据存储在真正的数据page之外
它的物理存储结构其实是这样的,在page页面中只会保留describe字段的前768个字节的前缀数据,之后是偏移量,偏移量指向存储完整数据的行溢出页。
到这里,其实对文章开头提出来的问题是有一个解答了。但是我们继续深入探索一下,什么样的数据会出现行溢出的这种现象呢?
行溢出的条件
有一些人认为像BLOB、LONGBLOB这类的大对象数据类型会把数据存放在数据页面之外。但是如果BLOB只存放了10个字段的数据,这时候还会把数据丢到其他页面吗?想来不会这么蠢,看资料别人的实验也证明了这一点。然后像varchar这样的类型,如果它存储了16K的内容,这些内容会存储在叶子节点内吗?事实证明也不合理。innodb是b+树的存储结构,在一个page中不希望只存储1条记录,是否发生行溢出这与page的大小有关系,一切都是为了保证一个page中存储多条数据,如果因为一条记录的超大导致了这个page存储不下其他的记录,显然在搜索效率上是无法容忍的。至于具体到怎样的数据级别,是超过9000个字节会存储或者其他,我个人认为这个和innodb 定义的page有关系。(个人理解,仅供参考,欢迎指正、探讨与交流)
来点赞吧,哈哈哈
字段类型大小表
字段类型 | 存储大小 | 解释 |
---|---|---|
CHAR | 0-255字节 | 定长字符串 |
VARCHAR | 0-65535 字节(64KB) | 变长字符串 |
TINYBLOB | 0-255字节 | 不超过 255个字符的二进制字符串 |
TINYTEXT | 0-255字节 | 短文本字符串 |
BLOB | 0-65 535字节(64KB) | 二进制形式的长文本数据 |
TEXT | 0-65 535字节(64KB) | 长文本数据 |
MEDIUMBL | OB 0-16 777 215字节(16M) | 二进制形式的中等长度文本数据 |
MEDIUMTE | XT 0-16 777 215字节(16M) | 中等长度文本数据 |
LONGBLOB | 0-4 294 967 295字节(4G) | 二进制形式的极大文本数据 |
LONGTEXT | 0-4 294 967 295字节(4G) | 极大文本数据 |
网友评论