InnoDB的存储格式已经有太多介绍性的文章,讲述了Tablespaces, Segments, Exents, Pages, Records等概念。其中很少有人对行存Record的不同数据字段进行介绍。本文讨论分析一下常见的字段数据在MySQL和InnoDB种不同的存储格式,并给出方法,大家可以自行学习其他没有涉及的字段。这里讨论的MySQL和InnoDB都是MySQL 5.7或MySQL 8.0, 过早的版本不在本文讨论范围。

因为MySQL可以对接不同独立的存储引擎,MySQL和其对应的存储引擎对数据的存储方式就可能不同。因此MySQL必然会在计算层和存储层有不同的存储格式,也会有对应的数据转化方法。

对于InnoDB而言,有两个方法对于数据格式的转化最为关键。

  1. MySQL数据 -> InnoDB数据 (row0mysql.cc)

大家可以使用GDB设置断点在以上两个函数,就可以清楚的认识到不同字段数据的存储格式了。

INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT

Table: Required Storage and Range for Integer Types Supported by MySQL

举例:BIGINT value 1000 InnoDB format 1000 stored as bigint (8 bytes) in Hex as: 0x80 0x00 0x00 0x00 0x00 0x00 0x03 0xe8 -1000 stored as bigint (8 bytes) in Hex as: 0x7f 0xff 0xff 0xff 0xff 0xff 0xfc 0x18

MySQL format: 1000 stored in Hex as: 0xe8 0x03 0x00 0x00 0x00 0x00 0x00 0x00

DECIMAL

这里MySQL和InnoDB存储格式一致,不需要做特别转换。Decimal需要声明precision和scale,例如decimal(30,15)。精度表示值存储的有效位数,小数位数表示小数点后可以存储的位数。

举例:decimal(30,15) value

1000.01 stored (14 bytes) in Hex as:

0x80 0x00 0x00 0x00 0x00 0x03 0xe8 0x00

0x98 0x96 0x80 0x00 0x00 0x00

FLOAT, DOUBLE

举例:double 1000.01 stored (8 bytes) in Hex as: 0xae 0x47 0xe1 0x7a 0x14 0x40 0x8f 0x40

Date and Time Data Types

时间相关的存储格式:

TypeStorage as of MySQL 5.6.4
YEAR1 byte, little endian
DATE3 bytes, little endian
TIME3 bytes + fractional-seconds storage, big endian
TIMESTAMP4 bytes + fractional-seconds storage, big endian
DATETIME5 bytes + fractional-seconds storage, big endian
  • TIME encoding for non-fractional part:
  • DATETIME encoding for non-fractional part:

举例: Datetime value: ‘1970-1-1 00:00:00’

  • innodb data: 0x99 0x02 0xc2 0x00 0x00

Datetime value: ‘2019-12-19 03:14:07’

  • innodb data: 0x99 0xa4 0xe6 0x33 0x87

还有其他常用字段大家可以通过前文的方法,自行学习下。在了解了不同字段的存储格式后,我们也可以从InnoDB落盘数据上得到验证。

找到对应table的数据文件,用hexdump把table数据以hex方式打印到一个文本文件内,然后就可以用编辑器打开浏览。这里可以结合上文中得到的不同字段hex的表示,在文本文件中搜寻。