TI的ISNULL()
一个懒惰的功能?
也就是说,如果我的代码类似如下:
SELECT ISNULL(MYFIELD, getMyFunction()) FROM MYTABLE
将它始终评估getMyFunction()
或将只在的情况下对其进行评估MYFIELD
实际上是空?
TI的ISNULL()
一个懒惰的功能?
也就是说,如果我的代码类似如下:
SELECT ISNULL(MYFIELD, getMyFunction()) FROM MYTABLE
将它始终评估getMyFunction()
或将只在的情况下对其进行评估MYFIELD
实际上是空?
这是任何一个它认为的最有效。
现在,它的功能与懒惰,这是最重要的事情。 例如,如果col1
是一个varchar
,这将始终包含一个号码时col2
为空,则
isnull(col2, cast(col1 as int))
将工作。
然而,它没有规定是否会之前或同时尝试投与空检查,如果吃错误col2
不为空,或者如果它只会尝试投在所有如果col2
为null。
最起码,我们希望它获得col1
在任何情况下,因为一个表中获得2个值的单次扫描将是快于两个扫描获得各一个。
同样的SQL命令可以在非常不同的方式来执行,因为我们给出的指令是基于对表的索引和统计信息的知识变成低级操作。
出于这个原因,在性能方面,得到的答案是“当它看起来这将是一个不错的主意是,否则就不是”。
在观察到的行为而言,这是懒惰。
编辑:埃里克森的Mikael的回答表明,有一些情况,可能是由于没有被懒惰确实错误。 我会用我的答案在这里坚守在性能影响方面,但他是在在至少某些情况下正确性影响而言至关重要。
这工作正常
declare @X int
set @X = 1
select isnull(@X, 1/0)
但是,引入的聚集将使其失败,证明第二个参数会之前,首先进行评估,有时。
declare @X int
set @X = 1
select isnull(@X, min(1/0))
从不同的言行举止
SELECT ISNULL(1, 1/0)
SELECT ISNULL(NULL, 1/0)
第一个SELECT返回1,第二个提出了一个Msg 8134, Level 16, State 1, Line 4 Divide by zero error encountered.
错误。
这种“懒人”功能,你指的其实是在所谓的“短路”
它不总是特别是如果你有在ISNULL表达UDF工作。
检查这篇文章在那里测试以证明这一点:
短路(主要是在VB.Net和SQL Server)
T-SQL是一个说明性语言,因此它无法控制用于获取结果的算法..它只是宣告什么样的结果,它需要。 这是高达查询引擎/优化找出符合成本效益的计划。 而在SQL Server中,优化器使用“矛盾检测”,这将永远无法保证左到右的评价,你会在程序语言承担。
对于你的榜样,做了一个快速测试:
创建标量值UDF零错误调用鸿沟:
CREATE FUNCTION getMyFunction
( @MyValue INT )
RETURNS INT
AS
BEGIN
RETURN (1/0)
END
GO
运行下面的查询没有给我一个Divide by zero error encountered
错误。
DECLARE @test INT
SET @test = 1
SET @test = ISNULL(@test, (dbo.getMyFunction(1)))
SELECT @test
更改SET
到以下声明没有给我Divide by zero error encountered.
错误。 (导入一个SELECT
在ISNULL
)
SET @test = ISNULL(@test, (SELECT dbo.getMyFunction(1)))
但随着值,而不是变量,它从来没有给我的错误。
SELECT ISNULL(1, (dbo.getMyFunction(1)))
SELECT ISNULL(1, (SELECT dbo.getMyFunction(1)))
所以,除非你真的找出优化器是怎样评估这些表达式的所有排列,这将是安全的,不依赖于T-SQL的短路能力。