为什么 COALESCE 会执行两次子查询?
Why does COALESCE execute the subquery twice?
我目前正在了解 ISNULL 和 COALESCE 之间的区别,并且我遇到了一个声明:
COALESCE((<subquery), 0)
翻译成(按照SQL标准):
CASE WHEN (<subquery>) IS NOT NULL THEN (<subquery>) ELSE 0 END
我的问题是:为什么子查询执行了两次?这似乎效率低下。
ISNULL()
与 SQL 服务器关联,所以这个问题似乎是关于 SQL 服务器的。正如评论中指出的那样,SQL 服务器 运行 两次子查询。
顺便说一下,这可能是有害的——而且不仅仅是子查询。考虑以下表达式:
select coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
它可以 return 一个 NULL
值 -- 尽管 COALESCE()
,因为第一个表达式被计算了两次。为了好玩,您可以 运行 这个查询:
select v.n, coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
from (values (1), (2), (3), (4), (5), (6), (7), (8)) v(n);
我可以推测 SQL 服务器会这样运行的几个原因。
(1) Microsoft 或 Sybase 的某些人(曾几何时)实际上认为这是正确的方法。
(2) 有人认为"we already have a function that does this, so COALESCE()
should be a little different"。即使那个"little difference"让它看起来像是坏了。
(3) SQL 服务器不会通过 运行 只优化子查询一次(据我所知)。因此,特别是对于子查询,想法可能是:"we'll fix this in a later round of optimization".
这都是猜测(因此也是观点)。我想回答,因为这不仅影响子查询。
我目前正在了解 ISNULL 和 COALESCE 之间的区别,并且我遇到了一个声明:
COALESCE((<subquery), 0)
翻译成(按照SQL标准):
CASE WHEN (<subquery>) IS NOT NULL THEN (<subquery>) ELSE 0 END
我的问题是:为什么子查询执行了两次?这似乎效率低下。
ISNULL()
与 SQL 服务器关联,所以这个问题似乎是关于 SQL 服务器的。正如评论中指出的那样,SQL 服务器 运行 两次子查询。
顺便说一下,这可能是有害的——而且不仅仅是子查询。考虑以下表达式:
select coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
它可以 return 一个 NULL
值 -- 尽管 COALESCE()
,因为第一个表达式被计算了两次。为了好玩,您可以 运行 这个查询:
select v.n, coalesce(case when rand(checksum(newid())) < 0.5 then 'a' end, 'b')
from (values (1), (2), (3), (4), (5), (6), (7), (8)) v(n);
我可以推测 SQL 服务器会这样运行的几个原因。
(1) Microsoft 或 Sybase 的某些人(曾几何时)实际上认为这是正确的方法。
(2) 有人认为"we already have a function that does this, so COALESCE()
should be a little different"。即使那个"little difference"让它看起来像是坏了。
(3) SQL 服务器不会通过 运行 只优化子查询一次(据我所知)。因此,特别是对于子查询,想法可能是:"we'll fix this in a later round of optimization".
这都是猜测(因此也是观点)。我想回答,因为这不仅影响子查询。