COALESCE 现在可以交易了吗?

Mit*_*tch 9 index sql-server sql-server-2016

我的一位开发人员认为COALESCE(column, default value) = default value现在可以使用了。那正确吗?

我进行了以下测试,并认为这意味着这COALESCE是不可分割的。

USE tempdb;

SELECT @@VERSION;
-- Microsoft SQL Server 2016 (RTM-CU3-GDR) (KB3194717) - 13.0.2186.6 (X64)   Oct 31 2016 18:27:32   Copyright (c) Microsoft Corporation  Developer Edition (64-bit) on Windows 10 Pro 6.3 <X64> (Build 14393: ) (Hypervisor) 

CREATE TABLE Test 
(
    ID int primary key clustered, 
    Mod6 int null, 
    INDEX IX_Mod6 NONCLUSTERED (Mod6)
);

INSERT INTO Test (ID, Mod6)
SELECT object_id as ID, case when name like '%k%' then null else object_id % 6 end as Mod6
FROM sys.objects;

SELECT Mod6
FROM Test WITH (INDEX = IX_Mod6, FORCESEEK)
where Mod6 is null or Mod6 = 0;
-- Plan shows expected seek

SELECT Mod6
FROM Test WITH (INDEX = IX_Mod6, FORCESEEK)
WHERE COALESCE(Mod6, 0) = 0;
-- Error:
-- Msg 8622, Level 16, State 1, Line 20
-- Query processor could not produce a query plan because of the hints 
-- defined in this query. Resubmit the query without specifying any hints 
-- and without using SET FORCEPLAN.
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 15

COALESCE是不可交易的。

您自己的测试很好地证明了这一点。

一个例外是,如果您使用COALESCE表达式创建了一个计算列并对其进行了索引。

CREATE TABLE Test 
(
    ID int primary key clustered, 
    Mod6 int null, 
    Foo AS COALESCE(Mod6, 0),
    INDEX IX_Mod6 NONCLUSTERED (Mod6),
    INDEX IX2_Mod6 NONCLUSTERED (Foo),
);
Run Code Online (Sandbox Code Playgroud)

你最终可能会寻求那个

SELECT Mod6
FROM Test WITH (INDEX = IX2_Mod6, FORCESEEK)
WHERE COALESCE(Mod6, 0) = 0;
Run Code Online (Sandbox Code Playgroud)

ISNULL 稍微更可讨论,因为如果它是完全冗余的,则可以对其进行优化并且不会阻止查找。

即如果列Mod6被定义为NOT NULL那么下面可以产生一个搜索。

SELECT Mod6
FROM Test 
WHERE ISNULL(Mod6, 0) = 0;
Run Code Online (Sandbox Code Playgroud)

但这当然不会比仅仅做任何好处

WHERE Mod6 = 0
Run Code Online (Sandbox Code Playgroud)