知识卡片
避免NULL是好原则,但用魔法值替代反而更容易出bug
内容
“尽量避免使用NULL”是一条常被提及的schema设计经验,但这条原则 经常被执行过头,变成”无论如何都要找个具体值来代替NULL”,而 这种矫枉过正反而会带来新的问题。用某个特定类型值域里”不可能 出现”的值来表示”未知”,看起来是绕开了NULL处理的麻烦,实际上 往往把问题转移到了别处:用-1代表一个未知的整数,代码里所有 读取这个字段的地方都必须记得”-1其实是个特殊标记,不是真的 -1”,一旦某处遗漏了这个判断,就会把”未知”当成”真实值-1”参与 计算,这类bug往往很隐蔽、不容易在测试阶段暴露。书中给出一个 常见的真实反例:用DATETIME类型的全零值”0000-00-00 00:00:00” 来表示”日期未知”,这种伪造的全0值同样会导致很多问题(时间 比较、排序、格式化这些操作都可能因为这个”合法但荒谬”的值出 岔子)。这说明”避免NULL”这条原则的真正意图,是提醒人们NULL 的三值逻辑(真/假/未知)容易被误用、容易引入不易察觉的逻辑 错误,而不是说”绝对不能用NULL”——当确实需要表达”这个值现在 就是未知的”这个语义时,NULL往往反而是比某个自造的魔法常数 更诚实、更不容易出错的选择,因为NULL至少会强制开发者显式处理 “未知”这个状态(比如用IS NULL判断),而一个魔法值很容易被 悄悄当成普通数据参与运算。任何”最佳实践”式的经验法则,都需要 回到它解决的具体问题上重新校准,而不是被当成不问场景的绝对 禁令。
参考来源
- 位置:《高性能MySQL:第3版》第4章"Schema与数据类型优化"4.2节
"MySQL schema设计中的陷阱"(源文件:
_epub-src/OEBPS/Text/part0011.xhtml)
- 结论依据:原文明确"我们之前写了避免使用NULL的好处……但是
遵循这个原则也不要走极端。当确实需要表示未知值时也不要害怕
使用NULL……从特定类型的值域中选择一个不可能的值,例如用−1
代表一个未知的整数,可能导致代码复杂很多,并容易引入bug……
伪造的全0值可能导致很多问题",直接说明用魔法值代替NULL的
具体风险及"避免NULL"原则不应被绝对化执行的立场。
- 原始内容:从特定类型的值域中选择一个不可能的值,例如用−1
代表一个未知的整数,可能导致代码复杂很多,并容易引入bug,
还可能会让事情变得一团糟。处理NULL确实不容易,但有时候会
比它的替代方案更好。