没有与Oracle功能的短路OR?

时间:2011-09-01 18:31:31

标签: sql oracle plsql short-circuiting

要允许超级用户/管理员登录我的系统,我正在运行(更大版本)此查询:

Select *
  From mytable
 Where (:id = 'Admin' Or :id = mytable.id);

如果我传递用户ID,我会获得该用户的所有数据;如果我传递字符串'Admin',我得所有数据。 这是有效的,因为Oracle的OR是short-circuit operator

但是,如果我将'Admin'设为一个包常量并使用函数来获取它,就像这样

Select *
  From mytable
 Where (:id = mypackage.GetAdminConstant Or :id = mytable.id);

当我通过'Admin'时,我得到ORA-01722: invalid number

为什么在引入函数时OR会失去其短路方面?

2 个答案:

答案 0 :(得分:6)

它不会失去短路方面。但SQL不是一种过程语言,并且不能保证多个谓词的评估顺序。

在C中,如果你写a || b,你就知道会先评估a,然后只在必要时评估b

在SQL中,如果您编写a OR b,您只知道将首先评估ab,并且将评估另一个表达式(至少在Oracle中)只在必要的时候。

查看两个查询的执行计划可能会给出评估顺序的一些指示,或者可能没有。

我猜想,在第一种情况下,Oracle可以看到第一个表达式对于每一行都具有相同的值,因此首先对其进行求值。当您更改为第二种情况时,Oracle现在会看到一个函数,每次计算时都会有不同的结果,因此它必须检查每一行,因此它会在执行函数调用之前尝试对列执行简单的相等性检查

我想知道如果你标记函数DETERMINISTIC会得到不同的结果,所以Oracle会知道它本质上是一个常数。

答案 1 :(得分:1)

最好使用2个绑定变量。

Select *
  From mytable
 Where (:admin = 'Admin' Or (:admin is null and :id = mytable.id));