知识卡片

字段默认NOT NULL:NULL的两个隐藏代价

普通读书笔记卡

内容

数据库开发规范里”所有字段均定义为NOT NULL,除非真的想存NULL”这条建议,背后有两个具体、可验证的技术理由,而不只是风格偏好。第一个代价是存储空间:InnoDB为了支持一个字段可以为NULL,需要额外用一个字节去标记这个字段当前是否为空,即使实际业务数据里这个字段几乎从不为空,这份额外开销依然存在——允许NULL本身就是有存储成本的,不是”不填就不占空间”这么简单。第二个代价更隐蔽也更严重:如果表内默认值为NULL的字段过多,会直接影响MySQL查询优化器选择执行计划的准确性——优化器在评估不同执行路径的代价时,需要依赖对数据分布的统计估算,大量NULL值会扰乱这些统计信息的可靠性,导致优化器可能选出一个实际上并不高效的执行计划,这个影响比单纯的存储空间浪费更难被直接察觉,往往要等到查询性能出问题、深入排查执行计划时才会被发现。这两个代价的性质不同:前者是确定的、可以直接计算出来的开销;后者是概率性的、可能在某些查询场景下才会显现的隐患。这个案例提示了一条评估”看似无害的默认设计选择”的重要原则:一个字段设计决策的真实代价,不能只看它最直观的那一面(这里是”是否需要额外存储标记位”),还要往下追问这个决策会不会通过某些不那么直接的路径(这里是”污染优化器的统计基础”),在系统运行的其他环节引发难以预料的连锁影响——尤其是数据库这类高度依赖内部统计信息做决策的系统,表结构设计上的一个”小”选择,完全可能在查询性能这个完全不同的维度上造成远超预期的影响。

参考来源

- 位置:《高可用架构(第1卷)》第5章《运维保障》"5.3 单表60亿记录等大数据场景的MySQL优化和运维之道"节,"5.3.2 数据库开发规范"(源文件:_epub-src/OEBPS/Text/Chapter5_3_3.xhtml) - 结论依据:原文说明"关于为什么定义不使用NULL的原因,有2种。浪费存储空间,因为InnoDB需要额外一个字节来存储。表内默认值NULL过多会影响优化器选择执行计划",直接支撑本卡片结论。 - 原始内容:所有字段均定义为NOT NULL,除非你真的想存NULL……关于为什么定义不使用NULL的原因,有2种。浪费存储空间,因为InnoDB需要额外一个字节来存储。表内默认值NULL过多会影响优化器选择执行计划。