วิธีตั้งค่ามุมมองที่จัดทำดัชนีไว้เมื่อเลือก TOP 1 ด้วย ORDER BY จากตารางที่แตกต่างกัน


11

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

    -- +++ THE QUERY THAT I WANT TO IMPROVE PERFORMANCE-WISE +++

    SELECT TOP 1 *
    FROM    dbo.TB_test1 t1
            INNER JOIN dbo.TB_test2 t2 ON t1.PK_ID1 = t2.FK_ID1
    ORDER BY t1.somethingelse1
           ,t2.somethingelse2;


    GO

การตั้งค่าตารางมีดังนี้:

  • สองตาราง
  • พวกเขาจะเข้าร่วมโดยการเข้าร่วมภายในโดยแบบสอบถามด้านบน
  • และเรียงลำดับโดยคอลัมน์จากคอลัมน์แรกจากนั้นคอลัมน์จากตารางที่สองโดยแบบสอบถามด้านบน เลือก TOP 1 เท่านั้น
  • (ในสคริปต์ด้านล่างมีบางบรรทัดเพื่อสร้างข้อมูลทดสอบในกรณีที่ช่วยทำให้เกิดปัญหา)

    -- +++ TABLE SETUP +++
    
    CREATE TABLE [dbo].[TB_test1]
        (
         [PK_ID1] [INT] IDENTITY(1, 1)  NOT NULL
        ,[something1] VARCHAR(40) NOT NULL
        ,[somethingelse1] BIGINT NOT NULL
            CONSTRAINT [PK_TB_test1] PRIMARY KEY CLUSTERED ( [PK_ID1] ASC )
        );
    
    GO
    
    create TABLE [dbo].[TB_test2]
        (
         [PK_ID2] [INT] IDENTITY(1, 1)  NOT NULL
        ,[FK_ID1] [INT] NOT NULL
        ,[something2] VARCHAR(40) NOT NULL
        ,[somethingelse2] BIGINT NOT NULL
            CONSTRAINT [PK_TB_test2] PRIMARY KEY CLUSTERED ( [PK_ID2] ASC )
        );
    
    GO
    
    ALTER TABLE [dbo].[TB_test2]  WITH CHECK ADD  CONSTRAINT [FK_TB_Test1] FOREIGN KEY([FK_ID1])
    REFERENCES [dbo].[TB_test1] ([PK_ID1])
    GO
    
    ALTER TABLE [dbo].[TB_test2] CHECK CONSTRAINT [FK_TB_Test1]
    
    GO
    
    
    -- +++ TABLE DATA GENERATION +++
    
    -- this might not be the quickest way, but it's only to set up test data
    
    INSERT INTO dbo.TB_test1
            ( something1, somethingelse1 )
    VALUES  ( CONVERT(VARCHAR(40), NEWID())  -- something1 - varchar(40)
              ,ISNULL(ABS(CHECKSUM(NewId())) % 92233720368547758078, 1)   -- somethingelse1 - bigint
              )
    
    GO 100000
    
    RAISERROR( 'Finished setting up dbo.TB_test1', 0, 1) WITH NOWAIT    
    
    GO    
    
    INSERT INTO dbo.TB_test2
            ( FK_ID1, something2, somethingelse2 )
    VALUES  ( ISNULL(ABS(CHECKSUM(NewId())) % ((SELECT MAX(PK_ID1) FROM dbo.TB_test1) - 1), 0) + 1 -- FK_ID1 - int
              ,CONVERT(VARCHAR(40), NEWID())  -- something2 - varchar(40)
              ,ISNULL(ABS(CHECKSUM(NewId())) % 92233720368547758078, 1)   -- somethingelse2 - bigint
              )
    
    GO 100000
    
    RAISERROR( 'Finished setting up dbo.TB_test2', 0, 1) WITH NOWAIT          
    
    GO

มุมมองที่มีการจัดทำดัชนีควรถูกกำหนดไว้ดังต่อไปนี้และแบบสอบถาม TOP 1 ที่เป็นผลลัพธ์อยู่ด้านล่าง แต่ดัชนีใดที่ฉันต้องการเพื่อให้แบบสอบถามนี้ทำงานได้ดีกว่าโดยไม่มีมุมมองที่จัดทำดัชนี?

    CREATE VIEW VI_test
    WITH SCHEMABINDING
    AS
        SELECT  t1.PK_ID1
               ,t1.something1
               ,t1.somethingelse1
               ,t2.PK_ID2
               ,t2.FK_ID1
               ,t2.something2
               ,t2.somethingelse2
        FROM    dbo.TB_test1 t1
                INNER JOIN dbo.TB_test2 t2 ON t1.PK_ID1 = t2.FK_ID1


    GO


    SELECT TOP 1 * FROM dbo.VI_test ORDER BY somethingelse1,somethingelse2


    GO

คำตอบ:


12

ดูเหมือนว่าจะละเว้นดัชนีใด ๆ ที่ฉันวางไว้

นอกจากว่าคุณกำลังใช้ SQL Server Enterprise Edition (หรือเทียบเท่า, Trial และ Developer) คุณจะต้องใช้WITH (NOEXPAND)ในการอ้างอิงมุมมองเพื่อใช้งาน ในความเป็นจริงแม้ว่าคุณจะใช้ Enterprise แต่ก็มีเหตุผลที่ดีที่จะใช้คำใบ้นั้น

เครื่องมือเพิ่มประสิทธิภาพการสืบค้น (ใน Enterprise Edition) อาจทำการเลือกตามต้นทุนระหว่างการใช้มุมมองที่ปรากฏหรือเข้าถึงตารางพื้นฐาน ในกรณีที่มุมมองมีขนาดใหญ่เท่าตารางพื้นฐานการคำนวณนี้อาจให้ความสำคัญกับตารางฐาน

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

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

สิ่งนี้จะลดขนาดของมุมมอง materialized และ จำกัด จำนวนการอัพเดตอัตโนมัติที่ต้องทำเพื่อให้มุมมองซิงโครไนซ์กับตารางฐาน จากนั้นคุณสามารถเขียนแบบสอบถามเพื่อดึงข้อมูลคีย์ 1 อันดับแรกตามลำดับที่ต้องการจากมุมมอง (ตามที่มีNOEXPAND) จากนั้นเข้าร่วมกลับไปที่ตารางฐานเพื่อดึงข้อมูลคอลัมน์ที่เหลือโดยใช้คีย์จากมุมมอง

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

ทางออกพื้นฐาน

CREATE VIEW VI_test
WITH SCHEMABINDING
AS
    SELECT
        t1.PK_ID1,
        t1.something1,
        t1.somethingelse1,
        t2.PK_ID2,
        t2.FK_ID1,
        t2.something2,
        t2.somethingelse2
    FROM dbo.TB_test1 t1
    INNER JOIN dbo.TB_test2 t2 
        ON t1.PK_ID1 = t2.FK_ID1;
GO
-- Brute force unique clustered index
CREATE UNIQUE CLUSTERED INDEX cuq 
ON dbo.VI_test 
    (somethingelse1, somethingelse2, PK_ID1, PK_ID2);
GO
SELECT TOP (1) * 
FROM dbo.VI_test WITH (NOEXPAND)
ORDER BY somethingelse1,somethingelse2;

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

ดัชนีกำลังดุร้าย

ใช้ดัชนี nonclustered

-- Minimal unique clustered index
CREATE UNIQUE CLUSTERED INDEX cuq 
ON dbo.VI_test 
    (PK_ID1, PK_ID2)
WITH (DROP_EXISTING = ON);
GO
-- Nonclustered index for ordering
CREATE NONCLUSTERED INDEX ix 
ON dbo.VI_test (somethingelse1, somethingelse2);

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

ดัชนีที่ไม่เป็นคลัสเตอร์สำหรับการสั่งซื้อ

มีการค้นหาในแผนนี้ แต่ใช้เพื่อดึงข้อมูลแถวเดียวเท่านั้น

มุมมองที่มีการจัดทำดัชนีน้อยที่สุด

ALTER VIEW VI_test
WITH SCHEMABINDING
AS
    SELECT
        t1.PK_ID1,
        t2.PK_ID2,
        t1.somethingelse1,
        t2.somethingelse2
    FROM dbo.TB_test1 t1
    INNER JOIN dbo.TB_test2 t2 
        ON t1.PK_ID1 = t2.FK_ID1;
GO
-- Unique clustered index
CREATE UNIQUE CLUSTERED INDEX cuq 
ON dbo.VI_test 
    (somethingelse1, somethingelse2, PK_ID1, PK_ID2);

ค้นหา:

SELECT TOP (1)
    V.PK_ID1,
    TT1.something1,
    V.somethingelse1,
    V.PK_ID2,
    TT2.FK_ID1,
    TT2.something2,
    V.somethingelse2
FROM dbo.VI_test AS V WITH (NOEXPAND)
JOIN dbo.TB_test1 AS TT1 ON TT1.PK_ID1 = V.PK_ID1
JOIN dbo.TB_test2 AS TT2 ON TT2.PK_ID2 = V.PK_ID2
ORDER BY somethingelse1,somethingelse2;

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

แผนแบบสอบถามสุดท้าย

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

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