Я только что взглянул на связанную статью и могу подтвердить, что короткое замыкание может дать сбой как для COALESCE, так и для ISNULL.
Кажется, что это не удастся, если у вас есть какой-либо подзапрос, но он прекрасно работает для скалярных функций и жестко закодированных значений.
Например,
DECLARE @test INT
SET @test = 1
PRINT 'test2'
SET @test = COALESCE(@test, (SELECT COUNT(*) FROM sysobjects))
SELECT 'test2', @test
-- OUCH, a scan through sysobjects
COALESCE реализован в соответствии со стандартом ANSI . Это просто сокращение для оператора CASE. ISNULL не является частью стандарта ANSI. Раздел 6.9, по-видимому, не требует явного короткого замыкания, но подразумевает, что должно быть возвращено первое истинное предложение в операторе when
.
Вот некоторые доказательства того, что это работает для скалярных функций (я запускал его на SQL Server 2005 ):
CREATE FUNCTION dbo.evil
(
)
RETURNS int
AS
BEGIN
-- 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 / 0
END
go
select dbo.evil()
-- takes forever
select ISNULL(1, dbo.evil())
-- very fast
select COALESCE(1, dbo.evil())
-- very fast
Вот некоторые доказательства того, что базовая реализация с CASE будет выполнять подзапросы.
DECLARE @test INT
SET @test = 1
select
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.