知识卡片
联结词的交换性陷阱:SQL求值顺序不能依赖联结词交换律
内容
逻辑上AND和OR都是可交换的:p AND q与q AND p逻辑等价,p OR q与
q 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
非负的测试完成之前就已经被调用了。