知识卡片
"太多列"的隐藏代价:行缓冲到行结构的转换开销
内容
一张表字段太多,直觉上的担心通常是”占用更多存储空间”,但 MySQL这套可插拔存储引擎架构下,真正容易被忽视的代价出在 另一个地方:存储引擎和服务器层之间通信靠的是行缓冲(row buffer)格式,服务器层拿到这份行缓冲后,需要把里面编码过的 各个列解码、转换成服务器层自己的行数据结构,这个转换操作本身 的开销会随列数增加而上升,和这一行里到底有多少数据无关,只和 列数量有关。这个开销是不是必然存在,还要看具体存储引擎: MyISAM的定长行结构碰巧和服务器层的行结构直接匹配,不需要 转换;但MyISAM的变长行结构和InnoDB的行结构,无论如何都需要 走这道转换流程。这意味着一张有几千个字段的”宽表”,即便真正 被用到的列只是其中一小部分,每次存取这一行时,转换开销依然 要按几千个字段的规模去付——不会因为大部分字段用不上就自动 省略这部分转换成本。这个具体案例揭示了一个更普遍的问题: “字段太多”的代价不完全体现在存储空间上,而是体现在每次 存储引擎和服务器层交互时都要重复付出的、和实际使用量无关的 固定转换开销上,这种开销在设计宽表schema时很容易被忽略, 因为它不会在”存储空间”这个直观指标上显现出来。
参考来源
- 位置:《高性能MySQL:第3版》第4章"Schema与数据类型优化"4.2节
"MySQL schema设计中的陷阱"(源文件:
_epub-src/OEBPS/Text/part0011.xhtml)
- 结论依据:原文明确"MySQL的存储引擎API工作时需要在服务器层和
存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲
内容解码成各个列。从行缓冲中将编码过的列转换成行数据结构的
操作代价是非常高的。MyISAM的定长行结构实际上与服务器层的
行结构正好匹配,所以不需要转换。然而,MyISAM的变长行结构和
InnoDB的行结构则总是需要转换。转换的代价依赖于列的数量……
客户使用了非常宽的表(数千个字段),然而只有一小部分列会
实际用到,这时转换的代价就非常高",直接说明列数与转换开销
的关系及具体案例。
- 原始内容:从行缓冲中将编码过的列转换成行数据结构的操作代价
是非常高的……转换的代价依赖于列的数量。当我们研究一个CPU
占用非常高的案例时,发现客户使用了非常宽的表(数千个字段),
然而只有一小部分列会实际用到,这时转换的代价就非常高。