HiveBrain v1.2.0
Get Started
← Back to all entries
patternsqlModerate

Is COALESCE sargable now?

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
nowsargablecoalesce

Problem

One of my developers is arguing that COALESCE(column, default value) = default value is now sargable. Is that right?

I ran the following test, and think it implies that COALESCE is non-sargable.

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  (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.

Solution

No COALESCE is not sargable.

Your own test demonstrates this well.

An exception would be if you created a computed column with the COALESCE expression and indexed that.

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),
);


You could end up with a seek on that

SELECT Mod6
FROM Test WITH (INDEX = IX2_Mod6, FORCESEEK)
WHERE COALESCE(Mod6, 0) = 0;


ISNULL is marginally more sargable in that if it is totally redundant it can be optimised out and not prevent a seek.

i.e. if the column Mod6 is defined as NOT NULL then the following can produce a seek.

SELECT Mod6
FROM Test 
WHERE ISNULL(Mod6, 0) = 0;


But this of course doesn't supply any benefit over just doing

WHERE Mod6 = 0

Code Snippets

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),
);
SELECT Mod6
FROM Test WITH (INDEX = IX2_Mod6, FORCESEEK)
WHERE COALESCE(Mod6, 0) = 0;
SELECT Mod6
FROM Test 
WHERE ISNULL(Mod6, 0) = 0;
WHERE Mod6 = 0

Context

StackExchange Database Administrators Q#162024, answer score: 15

Revisions (0)

No revisions yet.