COALESCE ไม่สามารถระบุได้ในตอนนี้


9

หนึ่งในนักพัฒนาของฉันกำลังโต้เถียงกันว่า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.

5
นักพัฒนาของคุณโต้แย้งด้วยหลักฐานใด ๆ หรือไม่?
Aaron Bertrand

ฉันอ่านโพสต์นี้: josef-richberg.squarespace.com/journal/2010/1/28/… ฉันไม่คิดว่าคำตอบที่เป็นรูปธรรมสามารถได้มาเพื่อตอบโพสต์นี้ (แต่อาจมีคนอื่นรู้ดีกว่า)
RLF

@RLF - บทความนั้นไม่ได้พูดอะไรที่บ่งบอกว่าเป็นเรื่องที่น่ารำคาญ นี่ไม่ใช่การสาธิตให้เห็นว่ามันน่ารำคาญ twitpic.com/107ms0 ความไม่สามารถทำได้คือการป้องกันการค้นหาคอลัมน์ที่ใช้ในการCASEแสดงออกไม่ใช่ว่าผลลัพธ์ของนิพจน์นั้นไม่สามารถนำมาใช้เพื่อค้นหาสิ่งอื่นได้
Martin Smith

@AaronBertrand "แผนการดำเนินการดูเหมือนกันไม่ว่าฉันจะเขียนอย่างไร" - เขาเพิกเฉยต่อความจริงที่ว่าไม่มีการดำเนินการค้นหาตามCOALESCEคอลัมน์ d
มิทช์

1
โอ้ฉันไม่ผิดที่ถามคำถามโดยเฉพาะอย่างยิ่งเมื่อคุณพยายามพิสูจน์หักล้างก่อน ฉันแค่บอกว่าบางทีนักพัฒนาของคุณควรเรียนรู้ที่จะทำแบบเดียวกัน
Aaron Bertrand

คำตอบ:


15

ไม่มีCOALESCEไม่ได้เป็น sargable

การทดสอบของคุณแสดงให้เห็นถึงสิ่งนี้ได้ดี

ข้อยกเว้นคือถ้าคุณสร้างคอลัมน์ที่คำนวณด้วย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),
);

คุณสามารถลงเอยด้วยการค้นหาสิ่งนั้น

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

ISNULL ถ้าหากมีการซ้ำซ้อนโดยสิ้นเชิงมันสามารถปรับให้เหมาะสมและไม่ป้องกันการค้นหา

นั่นคือถ้าคอลัมน์Mod6ถูกกำหนดเป็นNOT NULLแล้วต่อไปนี้สามารถสร้างการค้นหา

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

แต่แน่นอนว่านี่ไม่ได้ให้ประโยชน์อะไรเลย

WHERE Mod6 = 0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.