SARGable WHERE clause สำหรับสองคอลัมน์วันที่


24

ฉันมีคำถามที่น่าสนใจเกี่ยวกับ 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ในWHEREclause, CTEand, และแบบสอบถามสุดท้ายที่มีคำกริยาในคอลัมน์ที่คำนวณแล้วทั้งหมดให้แผนการ nicer ที่ดีกว่าด้วยการประมาณการที่ดีกว่าและทั้งหมดนั้น

ฉันสามารถอยู่กับสิ่งนี้ได้

สิ่งใดที่นำมาสู่คำถาม: ในแบบสอบถามเดียวมีวิธี SARGable เพื่อทำการค้นหานี้หรือไม่?

ไม่มีตารางชั่วคราวไม่มีตัวแปรตารางไม่มีการเปลี่ยนแปลงโครงสร้างตารางและไม่มีมุมมอง

ฉันสบายดีกับการรวมตัวเอง CTEs คำถามย่อยหรือการส่งผ่านข้อมูลหลายครั้ง สามารถทำงานกับ SQL Server รุ่นใดก็ได้

การหลีกเลี่ยงคอลัมน์ที่คำนวณเป็นข้อ จำกัด ที่ประดิษฐ์ขึ้นเพราะฉันสนใจโซลูชันการสืบค้นมากกว่าสิ่งอื่นใด

คำตอบ:


16

เพียงเพิ่มสิ่งนี้อย่างรวดเร็วเพื่อให้เป็นคำตอบ (แม้ว่าฉันรู้ว่าไม่ใช่คำตอบที่คุณต้องการ)

คอลัมน์ที่คำนวณแล้วที่มีการจัดทำดัชนีมักจะเป็นทางออกที่เหมาะสมสำหรับปัญหาประเภทนี้

มัน:

  • ทำให้ภาคแสดงการแสดงออกที่จัดทำดัชนี
  • ช่วยให้สามารถสร้างสถิติอัตโนมัติเพื่อการประมาณค่าเชิงปริมาณ
  • ไม่จำเป็นต้องใช้พื้นที่ในตารางฐาน

เพื่อให้ชัดเจนในจุดสุดท้ายนั้นคอลัมน์ที่คำนวณไม่จำเป็นต้องคงอยู่ในกรณีนี้:

-- Note: not PERSISTED, metadata change only
ALTER TABLE #sargme
ADD DayDiff AS DATEDIFF(DAY, DateCol1, DateCol2);

-- Index the expression
CREATE NONCLUSTERED INDEX index_name
ON #sargme (DayDiff)
INCLUDE (DateCol1, DateCol2);

ตอนนี้แบบสอบถาม:

SELECT
    S.ID,
    S.DateCol1,
    S.DateCol2,
    DATEDIFF(DAY, S.DateCol1, S.DateCol2)
FROM
    #sargme AS S
WHERE
    DATEDIFF(DAY, S.DateCol1, S.DateCol2) >= 48;

... ให้แผนไม่สำคัญดังต่อไปนี้:

แผนการดำเนินการ

ดังที่ Martin Smith กล่าวหากคุณมีการเชื่อมต่อโดยใช้ตัวเลือกชุดที่ไม่ถูกต้องคุณสามารถสร้างคอลัมน์ปกติและรักษาค่าที่คำนวณได้โดยใช้ทริกเกอร์

ทั้งหมดนี้เพียงจริงๆเรื่อง (ความท้าทายรหัสกัน) ถ้ามีปัญหาจริงที่จะแก้ปัญหาของหลักสูตรเป็นแอรอนกล่าวว่าในคำตอบของเขา

นี่เป็นเรื่องสนุกที่จะคิด แต่ฉันไม่รู้วิธีที่จะบรรลุสิ่งที่คุณต้องการโดยมีข้อ จำกัด ในคำถาม ดูเหมือนว่าทางออกที่ดีที่สุดจะต้องมีโครงสร้างข้อมูลใหม่บางประเภท; ที่ใกล้เคียงที่สุดเราได้เป็น 'ดัชนีฟังก์ชั่น' การประมาณที่จัดทำโดยดัชนีในคอลัมน์ที่คำนวณไม่ได้ดังต่อไปนี้


12

เสี่ยงต่อการเยาะเย้ยจากชื่อที่ยิ่งใหญ่ที่สุดในชุมชน SQL Server ฉันจะเอาคอพูดออกมาไม่ได้

เพื่อให้การค้นหาของคุณเป็น SARGable คุณจะต้องสร้างแบบสอบถามที่สามารถระบุแถวเริ่มต้นในช่วงของแถวที่อยู่ติดกันในดัชนี ด้วยดัชนีix_datesแถวจะไม่เรียงตามวันที่ระหว่างDateCol1และDateCol2เพื่อให้แถวเป้าหมายของคุณสามารถกระจายได้ทุกที่ในดัชนี

การรวมตัวเอง, การผ่านหลายครั้งและอื่น ๆ ล้วนมีเหมือนกันว่ามีการสแกนดัชนีอย่างน้อยหนึ่งครั้งแม้ว่าการเข้าร่วม (การวนซ้ำซ้อนกัน) อาจใช้การค้นหาดัชนีได้เป็นอย่างดี แต่ฉันไม่เห็นว่ามันจะกำจัดการสแกนได้อย่างไร

สำหรับการประมาณการแถวที่แม่นยำยิ่งขึ้นไม่มีสถิติเกี่ยวกับความแตกต่างของวันที่

โครงสร้าง CTE แบบเรียกซ้ำที่น่าเกลียดดังต่อไปนี้กำจัดเทคนิคการสแกนตารางทั้งหมดแม้ว่าจะแนะนำการเข้าร่วมลูปซ้อนและจำนวนดัชนี (อาจมีขนาดใหญ่มาก)

DECLARE @from date, @count int;
SELECT TOP 1 @from=DateCol1 FROM #sargme ORDER BY DateCol1;
SELECT TOP 1 @count=DATEDIFF(day, @from, DateCol1) FROM #sargme WHERE DateCol1<=DATEADD(day, -48, {d '9999-12-31'}) ORDER BY DateCol1 DESC;

WITH cte AS (
    SELECT 0 AS i UNION ALL
    SELECT i+1 FROM cte WHERE i<@count)

SELECT b.*
FROM cte AS a
INNER JOIN #sargme AS b ON
    b.DateCol1=DATEADD(day, a.i, @from) AND
    b.DateCol2>=DATEADD(day, 48+a.i, @from)
OPTION (MAXRECURSION 0);

มันสร้างดัชนีสปูลที่บรรจุทุกอย่างDateCol1ในตารางจากนั้นทำการค้นหาดัชนี (การสแกนช่วง) สำหรับแต่ละรายการDateCol1และDateCol2อย่างน้อย 48 วันข้างหน้า

มี IOs มากขึ้นเวลาดำเนินการที่นานขึ้นเล็กน้อยการประมาณแถวยังคงเป็นไปได้และไม่มีโอกาสเกิดการขนานเนื่องจากการเรียกซ้ำ: ฉันเดาว่าแบบสอบถามนี้อาจมีประโยชน์หากคุณมีค่าจำนวนมากภายในค่าค่อนข้างน้อยDateCol1(รักษาจำนวนการค้นหาลง)

แผนแบบสอบถาม CTE แบบเรียกซ้ำบ้า


9

ฉันลองใช้ชุดรูปแบบที่แปลกประหลาด แต่ไม่พบรุ่นใดที่ดีไปกว่ารุ่นใดรุ่นหนึ่งของคุณ ปัญหาหลักคือดัชนีของคุณมีลักษณะเช่นนี้ในแง่ของการเรียงลำดับวันที่ 1 และวันที่ 2 ด้วยกัน คอลัมน์แรกจะอยู่ในแนวที่ดีในขณะที่ช่องว่างระหว่างพวกเขาจะขรุขระมาก คุณต้องการให้สิ่งนี้ดูเหมือนเป็นช่องทางมากกว่าที่มันจะ:

Date1    Date2
-----    -------
*             *
*             *
*              *
 *       * 
 *        *
 *         *
  *      *
  *           *

ไม่มีทางใดที่ฉันจะคิดได้ว่าจะทำให้มันหาได้สำหรับเดลต้า (หรือช่วงเดลตา) ระหว่างจุดสองจุด และฉันหมายถึงการค้นหาครั้งเดียวที่ดำเนินการครั้งเดียว + สแกนช่วงไม่ใช่การค้นหาที่ดำเนินการสำหรับทุกแถว ซึ่งจะเกี่ยวข้องกับการสแกนและ / หรือการเรียงลำดับในบางจุดและสิ่งเหล่านี้เป็นสิ่งที่คุณต้องการหลีกเลี่ยงอย่างชัดเจน มันแย่เกินไปที่คุณไม่สามารถใช้นิพจน์เช่นDATEADD/ DATEDIFFในดัชนีที่กรองแล้วหรือดำเนินการแก้ไขสคีมาใด ๆ ที่อาจทำให้เกิดการเรียงลำดับบนผลิตภัณฑ์ของวันที่ต่างกัน (เช่นการคำนวณเดลตาที่เวลาแทรก / อัปเดต) ตามที่เป็นอยู่นี้เป็นหนึ่งในกรณีที่การสแกนเป็นวิธีการดึงข้อมูลที่ดีที่สุด

คุณบอกว่าการสืบค้นนี้ไม่สนุก แต่ถ้าคุณดูให้ใกล้กว่านี้จะเป็นการดีที่สุด (และจะดียิ่งขึ้นถ้าคุณออกการคำนวณสเกลาร์ผลลัพธ์):

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [#sargme] AS [s]
WHERE
    [s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])

เหตุผลก็คือการหลีกเลี่ยงDATEDIFFอาจโกน CPU บางเมื่อเทียบกับการคำนวณกับเพียงคอลัมน์คีย์ไม่ใช่ชั้นนำในดัชนีและยังหลีกเลี่ยงการแปลงนัยบางอย่างที่น่ารังเกียจdatetimeoffset(7)(อย่าถามฉันว่าทำไมเหล่านี้จะมี แต่พวกเขามี) นี่คือDATEDIFFรุ่น:

<Predicate>
<ScalarOperator ScalarString = "ลงวันที่ (วัน CONVERT_IMPLICIT (datetimeoffset (7), [splunge]. [dbo]. [sargme]. [DateCol1] เป็น [s] [DateCol1], 0 7), [splunge]. [dbo]. [sargme]. [DateCol2] เป็น [s]. [DateCol2], 0))> = (48) ">

และนี่คือสิ่งที่ไม่มีDATEDIFF:

<Predicate>
<ScalarOperator ScalarString = "[splunge]. [dbo]. [sargme]. [DateCol2] เป็น [s]. [DateCol2]> = dateadd (วัน (48), [splunge]. [dbo] sargme]. [DateCol1] เป็น [s]. [DateCol1]) ">

นอกจากนี้ฉันยังพบผลลัพธ์ที่ดีขึ้นเล็กน้อยในแง่ของระยะเวลาเมื่อฉันเปลี่ยนดัชนีเป็นรวม เท่านั้นDateCol2(และเมื่อดัชนีทั้งสองปรากฏอยู่ SQL Server มักจะเลือกหนึ่งด้วยคีย์เดียวและหนึ่งรวมคอลัมน์กับหลายคีย์) สำหรับแบบสอบถามนี้เนื่องจากเราต้องสแกนแถวทั้งหมดเพื่อหาช่วงอย่างไรก็ตามก็ไม่มีประโยชน์ที่จะมีคอลัมน์วันที่ที่สองเป็นส่วนหนึ่งของคีย์และเรียงลำดับในทางใดทางหนึ่ง และในขณะที่ฉันรู้ว่าเราไม่สามารถค้นหาได้ที่นี่มีบางสิ่งที่ดีโดยเนื้อแท้เกี่ยวกับการไม่ขัดขวางความสามารถในการรับโดยบังคับให้คำนวณกับคอลัมน์คีย์หลักและดำเนินการกับคอลัมน์รองหรือรวมเท่านั้น

ถ้าเป็นฉันและฉันยอมแพ้ในการหาวิธีแก้ปัญหา sargable ฉันรู้ว่าฉันจะเลือกอันไหน - อันที่ทำให้ SQL Server ทำงานได้น้อยที่สุด (แม้ว่าเดลต้าจะแทบไม่มีเลย) หรือดีกว่ายังฉันจะผ่อนคลายข้อ จำกัด ของฉันเกี่ยวกับการเปลี่ยนแปลงสคีมาและไม่ชอบ

และทั้งหมดนั้นมีความสำคัญมากแค่ไหน? ฉันไม่รู้ ฉันสร้างตาราง 10 ล้านแถวและรูปแบบข้อความค้นหาทั้งหมดข้างต้นยังคงเสร็จสมบูรณ์ภายในไม่กี่วินาที และนี่คือบน VM บนแล็ปท็อป (ที่ได้รับพร้อมกับ SSD)


3

ทุกวิธีที่ฉันคิดว่าจะทำให้ WHERE ประโยค sarg-can มีความซับซ้อนและรู้สึกว่าการทำงานต่อดัชนีพยายามเป็นเป้าหมายสุดท้ายไม่ใช่วิธีการ ดังนั้นไม่ฉันไม่คิดว่าเป็นไปได้ (ในทางปฏิบัติ) เป็นไปได้

ฉันไม่แน่ใจว่า "ไม่มีการเปลี่ยนแปลงโครงสร้างตาราง" หมายความว่าไม่มีดัชนีเพิ่มเติม ต่อไปนี้เป็นโซลูชันที่หลีกเลี่ยงการสแกนดัชนีอย่างสมบูรณ์ แต่ส่งผลให้ค้นหาดัชนีแยกกันจำนวนมากเช่นหนึ่งรายการสำหรับแต่ละDateCol1 ที่เป็นไปได้ในช่วง Min / Max ของค่าวันที่ในตาราง (ซึ่งแตกต่างจากของแดเนียลซึ่งส่งผลให้หนึ่งค้นหาสำหรับแต่ละวันที่แตกต่างกันที่ปรากฏจริงในตาราง) ในทางทฤษฎีมันเป็นผู้สมัครสำหรับการขนาน b / c มันหลีกเลี่ยงการเรียกซ้ำ แต่จริงๆแล้วมันยากที่จะเห็นการกระจายข้อมูลที่สิ่งนี้เร็วกว่าการสแกนและทำ DATEDIFF (อาจเป็น DOP ที่สูงจริงๆเหรอ) และ ... รหัสนั้นน่าเกลียด ฉันเดาว่าความพยายามนี้นับเป็น "การออกกำลังกายทางจิต"

--Add this index to avoid the scan when determining the @MaxDate value
--CREATE NONCLUSTERED INDEX [ix_dates2] ON [#sargme] ([DateCol2]);
DECLARE @MinDate DATE, @MaxDate DATE;
SELECT @MinDate=DateCol1 FROM (SELECT TOP 1 DateCol1 FROM #sargme ORDER BY DateCol1 ASC) ss;
SELECT @MaxDate=DateCol2 FROM (SELECT TOP 1 DateCol2 FROM #sargme ORDER BY DateCol2 DESC) ss;

--Used 44 just to get a few more rows to test my logic
DECLARE @DateDiffSearchValue INT = 44, 
    @MinMaxDifference INT = DATEDIFF(DAY, @MinDate, @MaxDate);

--basic data profile in the table
SELECT [MinDate] = @MinDate, 
        [MaxDate] = @MaxDate, 
        [MinMaxDifference] = @MinMaxDifference, 
        [LastDate1SearchValue] = DATEADD(DAY, 0-@DateDiffSearchValue, @MaxDate);

;WITH rn_base AS (
SELECT [col1] = 0
        UNION ALL SELECT 0
        UNION ALL SELECT 0
        UNION ALL SELECT 0
),
rn_1 AS (
    SELECT t0.col1 FROM rn_base t0
        CROSS JOIN rn_base t1
        CROSS JOIN rn_base t2
        CROSS JOIN rn_base t3
),
rn_2 AS (
    SELECT rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM rn_1 t0
        CROSS JOIN rn_1 t1
),
candidate_searches AS (
    SELECT 
        [Date1_EqualitySearch] = DATEADD(DAY, t.rn-1, @MinDate),
        [Date2_RangeSearch] = DATEADD(DAY, t.rn-1+@DateDiffSearchValue, @MinDate)
    FROM rn_2 t
    WHERE DATEADD(DAY, t.rn-1, @MinDate) <= DATEADD(DAY, 0-@DateDiffSearchValue, @MaxDate)
    /* Of course, ignore row-number values that would result in a
       Date1_EqualitySearch value that is < @DateDiffSearchValue days before @MaxDate */
)
--select * from candidate_searches

SELECT c.*, xapp.*, dd_rows = DATEDIFF(DAY, xapp.DateCol1, xapp.DateCol2)
FROM candidate_searches c
    cross apply (
        SELECT t.*
        FROM #sargme t
        WHERE t.DateCol1 = c.date1_equalitysearch
        AND t.DateCol2 >= c.date2_rangesearch
    ) xapp
ORDER BY xapp.ID asc --xapp.DateCol1, xapp.DateCol2 

3

คำตอบ Community Wiki แรกเริ่มถูกเพิ่มโดยผู้เขียนคำถามเป็นการแก้ไขคำถาม

หลังจากที่ปล่อยให้นั่งนี้สักครู่และบางคนที่ฉลาดจริง ๆ ตีระฆังความคิดเริ่มต้นของฉันในเรื่องนี้ดูเหมือนว่าถูกต้อง: ไม่มีวิธีที่มีเหตุผลและ SARGable ในการเขียนแบบสอบถามนี้โดยไม่ต้องเพิ่มคอลัมน์คำนวณหรือบำรุงรักษาผ่านกลไกอื่น ๆ ทริกเกอร์

ฉันลองทำอย่างอื่นและฉันมีข้อสังเกตอื่นที่น่าสนใจสำหรับทุกคนที่อ่าน

ก่อนอื่นให้เรียกใช้การตั้งค่าอีกครั้งโดยใช้ตารางปกติแทนที่จะเป็นตารางชั่วคราว

  • แม้ว่าฉันจะรู้จักชื่อเสียงของพวกเขา แต่ฉันต้องการลองใช้สถิติแบบหลายคอลัมน์ พวกเขาไร้ประโยชน์
  • ฉันต้องการดูสถิติที่ใช้

นี่คือการตั้งค่าใหม่:

USE [tempdb]
SET NOCOUNT ON  

DBCC FREEPROCCACHE

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])

CREATE STATISTICS [s_sargme] ON [sargme] ([DateCol1], [DateCol2])

จากนั้นเรียกใช้คิวรีแรกจะใช้ดัชนี ix_dates และสแกนเหมือนเมื่อก่อน ไม่มีการเปลี่ยนแปลงที่นี่ ดูเหมือนว่าจะซ้ำซ้อน แต่ติดกับฉัน

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [sargme] AS [s]
WHERE
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) >= 48

เรียกใช้แบบสอบถาม CTE อีกครั้งยังคงเหมือนเดิม ...

WITH    [x] AS ( SELECT
                * ,
                DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) AS [ddif]
               FROM
                [sargme] AS [s])
     SELECT
        *
     FROM
        [x]
     WHERE
        [x].[ddif] >= 48;

เอาล่ะ! เรียกใช้แบบสอบถามที่ไม่สามารถเปรียบเทียบได้ครึ่งอีกครั้ง:

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [sargme] AS [s]
WHERE
    [s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])

ตอนนี้เพิ่มคอลัมน์ที่คำนวณแล้วและเรียกใช้ทั้งสามใหม่พร้อมกับแบบสอบถามที่พบคอลัมน์ที่คำนวณแล้ว:

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

ถ้าคุณติดกับฉันไปที่นี่ขอบคุณ นี่คือส่วนการสังเกตที่น่าสนใจของโพสต์

การเรียกใช้แบบสอบถามด้วยการตั้งค่าสถานะการสืบค้นกลับที่ไม่มีเอกสารโดยFabiano Amorimเพื่อดูว่าสถิติการสืบค้นแต่ละรายการที่ใช้นั้นค่อนข้างดี การเห็นว่าไม่มีแผนสัมผัสวัตถุสถิติจนกว่าคอลัมน์ที่คำนวณถูกสร้างขึ้นและการจัดทำดัชนีดูแปลก ๆ

สิ่งที่เกิดขึ้นนองเลือด

Heck แม้แต่ข้อความค้นหาที่ตีคอลัมน์ที่คำนวณแล้วเท่านั้นไม่ได้แตะวัตถุสถิติจนกว่าฉันจะเรียกใช้สองสามครั้งและได้รับการทำให้เป็นพารามิเตอร์ง่าย ๆ ดังนั้นถึงแม้ว่าพวกเขาทั้งหมดจะสแกนดัชนี ix_dates ในตอนแรกพวกเขาใช้การประมาณค่าความสำคัญของการเข้ารหัสแบบดิจิตัล (30% ของตาราง) แทนที่จะเป็นวัตถุสถิติใด ๆ

อีกจุดหนึ่งที่ยกคิ้วขึ้นตรงนี้คือเมื่อฉันเพิ่มเฉพาะดัชนีที่ไม่เป็นคลัสเตอร์แบบสอบถามจะวางแผนสแกน HEAP ทั้งหมดแทนที่จะใช้ดัชนีที่ไม่ใช่คลัสเตอร์ในคอลัมน์วันที่ทั้งสอง

ขอบคุณทุกคนที่ตอบกลับ คุณยอดเยี่ยมมาก

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