COALESCE é sargável agora?

9

Um dos meus desenvolvedores está argumentando que COALESCE(column, default value) = default valueagora é sargável. Isso está certo?

Fiz o teste a seguir e acho que isso COALESCEnão é sargável.

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.
Mitch
fonte
5
Seu desenvolvedor argumentou com alguma evidência?
Aaron Bertrand
Eu li este post: josef-richberg.squarespace.com/journal/2010/1/28/… Eu não acho que uma resposta concreta possa ser derivada para responder a este post. (Mas talvez alguém sabe melhor.)
RLF
@RLF - esse artigo não diz nada que indique que é sargável. Isso não é uma demonstração de que é sargável. twitpic.com/107ms0 . A não sargabilidade é que ela impede uma busca nas colunas usadas na CASEexpressão - não que o resultado da expressão não possa ser usado para procurar outra coisa.
Martin Smith
@AaronBertrand, "O plano de execução parecia o mesmo, não importa como eu o escrevesse" - ele ignorou o fato de que nenhum dos dois estava realizando uma busca com base na COALESCEcoluna d.
Mitch
11
Ah, eu não culpo você por fazer a pergunta, principalmente porque você tentou refutá-la primeiro. Eu estava apenas sugerindo que talvez seu desenvolvedor devesse aprender a fazer o mesmo.
Aaron Bertrand

Respostas:

15

Não, COALESCEnão é sargável.

Seu próprio teste demonstra isso bem.

Uma exceção seria se você criasse uma coluna computada com a COALESCEexpressão e a indexasse.

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

Você pode acabar com uma busca nesse

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

ISNULL é marginalmente mais sargável, pois se for totalmente redundante, pode ser otimizado e não impedir uma busca.

ou seja, se a coluna Mod6for definida como NOT NULL, o seguinte poderá produzir uma busca.

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

Mas isso, obviamente, não oferece nenhum benefício em apenas fazer

WHERE Mod6 = 0
Martin Smith
fonte