知识卡片

联结词的交换性陷阱:SQL求值顺序不能依赖联结词交换律

普通读书笔记卡

内容

逻辑上AND和OR都是可交换的:p AND qq AND p逻辑等价,p OR qq OR p逻辑等价——这是纯粹的真值判定层面的性质,不涉及任何”先算哪个”的 执行顺序含义。这条性质带来一条容易被忽视的编码原则:永远不要在代码中依赖 “p一定先于q求值”这种假设,因为逻辑等价性只保证最终真值一致,不保证也不 应该保证任何特定的求值顺序。书中给出一个具体反例:假设SQRT函数在参数为 负数时会抛异常,那么SQL表达式WHERE X>=0 AND SQRT(X)<=100并不能保证不 抛异常——因为AND的可交换性意味着系统完全可以先计算SQRT(X)<=100,只要 系统认为这样做在某些场合更高效(这正呼应[[表达式变换与优化的分配律交换律 结合律]]中优化器可以自由重排满足交换律的运算这条原则)。这个陷阱提醒开发者: 凡是逻辑上等价、可交换的运算,就不能把”求值顺序恰好符合书写顺序”当作程序 正确性的隐含前提,任何依赖特定求值顺序才能避免出错的代码,在语义上都是脆弱 且不可靠的写法。

参考来源

- 位置:《SQL与关系数据库理论——如何编写健壮的SQL代码》第10章"SQL与逻辑" 10.2.2节"关于交换性的说明"(源文件:OEBPS/text00110.html) - 结论依据:原文明确"联结词AND和OR是可交换的……复合命题p AND q和q AND p 是逻辑等价的……永远不要在代码中包含一个假设p比q(或q比p)先求值的命题 ……这个表达式并不保证不抛出异常,因为SQRT函数可能在确保X非负的测试完成 之前就已经被调用了"。 - 原始内容:联结词AND和OR是可交换的……永远不要在代码中包含一个假设p比q 先求值的命题……这个表达式并不保证不抛出异常,因为SQRT函数可能在确保X 非负的测试完成之前就已经被调用了。