ฉันมีคำถามที่น่าสนใจเกี่ยวกับ SARGability คืออะไร ในกรณีนี้มันเกี่ยวกับการใช้เพรดิเคตกับความแตกต่างระหว่างสองคอลัมน์วันที่ นี่คือการตั้งค่า:
USE [tempdb]
SET NOCOUNT ON
IF OBJECT_ID('tempdb..#sargme') IS NOT NULL
BEGIN
DROP TABLE #sargme
END
SELECT TOP 1000
IDENTITY (BIGINT, 1,1) AS ID,
CAST(DATEADD(DAY, [m].[severity] * -1, GETDATE()) AS DATE) AS [DateCol1],
CAST(DATEADD(DAY, [m].[severity], GETDATE()) AS DATE) AS [DateCol2]
INTO #sargme
FROM sys.[messages] AS [m]
ALTER TABLE [#sargme] ADD CONSTRAINT [pk_whatever] PRIMARY KEY CLUSTERED ([ID])
CREATE NONCLUSTERED INDEX [ix_dates] ON [#sargme] ([DateCol1], [DateCol2])
สิ่งที่ฉันจะเห็นบ่อยๆเป็นอะไรแบบนี้:
/*definitely not sargable*/
SELECT
* ,
DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
[#sargme] AS [s]
WHERE
DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) >= 48;
... ซึ่งแน่นอนว่าไม่ใช่ SARGable มันส่งผลในการสแกนดัชนีอ่าน 1,000 แถวทั้งหมดไม่ดี แถวโดยประมาณมีกลิ่นเหม็น คุณไม่เคยทำสิ่งนี้ในการผลิต
มันจะดีถ้าเราสามารถทำให้ CTE เป็นจริงได้เพราะนั่นจะช่วยให้เราทำสิ่งนี้ได้ดีขึ้น SARGable-er พูดทางเทคนิค แต่ไม่เราได้รับแผนการดำเนินการเช่นเดียวกับด้านบน
/*would be nice if it were sargable*/
WITH [x] AS ( SELECT
* ,
DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) AS [ddif]
FROM
[#sargme] AS [s])
SELECT
*
FROM
[x]
WHERE
[x].[ddif] >= 48;
และแน่นอนเนื่องจากเราไม่ได้ใช้ค่าคงที่รหัสนี้ไม่มีอะไรเปลี่ยนแปลงและไม่ได้ครึ่ง SARGable ไม่สนุก. แผนการดำเนินการเดียวกัน
/*not even half sargable*/
SELECT
* ,
DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
[#sargme] AS [s]
WHERE
[s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])
หากคุณรู้สึกโชคดีและคุณเชื่อฟังตัวเลือก ANSI SET ทั้งหมดในสตริงการเชื่อมต่อของคุณคุณสามารถเพิ่มคอลัมน์ที่คำนวณได้และค้นหาใน ...
ALTER TABLE [#sargme] ADD [ddiff] AS
DATEDIFF(DAY, DateCol1, DateCol2) PERSISTED
CREATE NONCLUSTERED INDEX [ix_dates2] ON [#sargme] ([ddiff], [DateCol1], [DateCol2])
SELECT [s].[ID] ,
[s].[DateCol1] ,
[s].[DateCol2]
FROM [#sargme] AS [s]
WHERE [ddiff] >= 48
สิ่งนี้จะทำให้คุณค้นหาดรรชนีโดยมีสามเคียวรี คนแปลกหน้าคือที่ที่เราเพิ่ม 48 วันใน DateCol1 แบบสอบถามที่มีDATEDIFF
ในWHERE
clause, CTE
and, และแบบสอบถามสุดท้ายที่มีคำกริยาในคอลัมน์ที่คำนวณแล้วทั้งหมดให้แผนการ nicer ที่ดีกว่าด้วยการประมาณการที่ดีกว่าและทั้งหมดนั้น
สิ่งใดที่นำมาสู่คำถาม: ในแบบสอบถามเดียวมีวิธี SARGable เพื่อทำการค้นหานี้หรือไม่?
ไม่มีตารางชั่วคราวไม่มีตัวแปรตารางไม่มีการเปลี่ยนแปลงโครงสร้างตารางและไม่มีมุมมอง
ฉันสบายดีกับการรวมตัวเอง CTEs คำถามย่อยหรือการส่งผ่านข้อมูลหลายครั้ง สามารถทำงานกับ SQL Server รุ่นใดก็ได้
การหลีกเลี่ยงคอลัมน์ที่คำนวณเป็นข้อ จำกัด ที่ประดิษฐ์ขึ้นเพราะฉันสนใจโซลูชันการสืบค้นมากกว่าสิ่งอื่นใด