回答

收藏

COALESCE-保证短路?

技术问答 技术问答 300 人阅读 | 0 人回复 | 2023-09-14

从这个问题出发,是关于使用的COALESCE简化复杂逻辑树的简洁答案。我考虑了短路。: d2 a9 j6 L- q0 Q) M/ s- _
例如,在大多数语言函数中,对参数进行综合评估,然后传递给函数。C中:3 o  W# x( D: E  ~% X
int f(float x,float y)    return x;}f(a,a / b) ; // This will result in an error if b == 0这似乎不是COALESCESQL Server中功能的限制:
2 I5 |+ W. U9 ?1 h& o# DAS TestCalcFROM FractionsDROP TABLE Fractions       0    ) AS TestCalcFROM FractionsDROP TABLE Fractions假如它正在评估分母= 0的第二种情况,那么我期待看到以下类似的错误:
. u6 T" z1 R  c6 L* _- k/ ]Msg 8134,Level 16,State 1,Line 1Divide by zero error encountered.我发现了一些提到1 R9 g( [- M6 _( Z
相关甲骨文。并使用。SQL
0 c1 O6 e/ F6 C0 Z( E6 _Server进行了一些测试。包含用户定义函数时,短路可能会中断。
$ Q+ B' C# x: x! f8 ~" k那么,这种行为应该由吗?ANSI保证标准?1 }! R4 G! n3 t7 D# d# I& u
                                                                * w5 Y8 I2 `8 g' a; y, B" {3 f2 O
    解决方案:                                                                . c* s2 `( q6 E  V3 G
                                                                我只是看了链接的文章,可以确认短路COALESCE和ISNULL都可能失败。# j) q$ D2 D! W& U3 o5 n8 F
如果涉及到任何子查询,它似乎会失败,但是它对于标量函数和硬编码值可以正常工作。9 z) t* k) O3 ?4 `0 L$ h5 F
例如,
/ i$ j- S( T1 s- e& MDECLARE @test INTSET @test = 1PRINT 'test2'SET @test = COALESCE(@test,(SELECT COUNT(*) FROM sysobjects))SELECT 'test2',@test-- OUCH,a scan through sysobjectsCOALESCE是根据ANSI实施标准CASE句子的简写形式。ISNULL不是ANSI标准的一部分.9节似乎没有明确要求短路,但它确实暗示when应返回句子中的第一个true子句。
6 ?8 I3 o7 p& l( T7 w0 s这是一些适合基于标量函数的证明(我在SQL Server9 f+ e, i$ O1 Y
它在2005上运行):
' l# y8 }/ |' u/ p5 GCREATE FUNCTION dbo.evil()RETURNS intASBEGIN    -- Create an huge delay    declare @c int    select @c = count(*) from sysobjects a    join sysobjects b on 1=1    join sysobjects c on 1=1    join sysobjects d on 1=1    join sysobjects e on 1=1    join sysobjects f on 1=1    return @c / 0ENDgoselect dbo.evil()-- takes foreverselect ISNULL(1, dbo.evil())-- very fastselect COALESCE(1, dbo.evil())-- very fast这证明CASE执行子查询的基础实现。
7 J0 }+ x7 r3 [, D* }% ]& uDECLARE @test INTSET @test = 1select    case        when @test is not null then @test        when @test = 2 then (SELECT COUNT(*) FROM sysobjects)        when 1=0 then (SELECT COUNT(*) FROM sysobjects)        else (SELECT COUNT(*) FROM sysobjects)    end-- OUCH,two table scans. If 1=0,it does not result in a table scan.
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则