Cách thiết lập chế độ xem được lập chỉ mục khi CHỌN TOP 1 với ORDER BY từ các bảng khác nhau


11

Tôi đang vật lộn để thiết lập chế độ xem được lập chỉ mục trong kịch bản sau để truy vấn sau thực hiện mà không có hai lần quét chỉ mục được nhóm. Bất cứ khi nào tôi tạo chế độ xem chỉ mục cho truy vấn này và sau đó sử dụng nó, nó dường như bỏ qua bất kỳ chỉ mục nào tôi đặt trên nó:

    -- +++ 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

Thiết lập bảng như sau:

  • hai cái bàn
  • họ được tham gia bởi một tham gia bên trong bởi các truy vấn ở trên
  • và được sắp xếp theo một cột từ đầu tiên và sau đó là một cột từ bảng thứ hai bằng truy vấn ở trên; chỉ TOP 1 được chọn
  • (trong đoạn script bên dưới cũng có một số dòng để tạo dữ liệu thử nghiệm, chỉ trong trường hợp nó giúp tái tạo vấn đề)

    -- +++ 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

Chế độ xem được lập chỉ mục có thể được xác định như sau và kết quả truy vấn TOP 1 bên dưới. Nhưng tôi cần những chỉ mục nào để truy vấn này hoạt động tốt hơn so với không có chế độ xem được lập chỉ mục?

    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

Câu trả lời:


12

Dường như bỏ qua bất kỳ chỉ số nào tôi đặt trên nó

Trừ khi bạn đang sử dụng SQL Server Enterprise Edition (hoặc tương đương, Bản dùng thử và Nhà phát triển), bạn sẽ cần sử dụng WITH (NOEXPAND) trên tham chiếu chế độ xem để sử dụng nó. Trên thực tế, ngay cả khi bạn đang sử dụng Enterprise, vẫn có những lý do chính đáng để sử dụng gợi ý đó .

Nếu không có gợi ý, trình tối ưu hóa truy vấn (trong Phiên bản doanh nghiệp) có thể đưa ra lựa chọn dựa trên chi phí giữa việc sử dụng chế độ xem cụ thể hóa hoặc truy cập các bảng cơ sở. Trong đó chế độ xem lớn như các bảng cơ sở, phép tính này có thể có lợi cho các bảng cơ sở.

Một điểm đáng chú ý nữa là không có NOEXPAND gợi ý, các tham chiếu xem luôn được mở rộng đến truy vấn cơ sở trước khi bắt đầu tối ưu hóa. Khi tối ưu hóa tiến triển, trình tối ưu hóa có thể hoặc không thể khớp định nghĩa mở rộng trở lại chế độ xem cụ thể hóa, tùy thuộc vào hoạt động tối ưu hóa trước đó. Điều này gần như chắc chắn không phải là trường hợp với truy vấn đơn giản của bạn, nhưng tôi đề cập đến nó cho đầy đủ.

Vì vậy, sử dụng NOEXPAND gợi ý bảng là tùy chọn chính của bạn, nhưng bạn cũng có thể nghĩ về việc chỉ cụ thể hóa các phím của bảng cơ sở và các cột cần thiết để đặt hàng trong dạng xem. Tạo một chỉ mục được nhóm duy nhất trên các cột khóa kết hợp, sau đó là một chỉ mục không tách rời riêng biệt trên các cột đặt hàng.

Điều này sẽ giảm kích thước của chế độ xem được cụ thể hóa và giới hạn số lượng cập nhật tự động phải được thực hiện để giữ cho chế độ xem được đồng bộ hóa với các bảng cơ sở. Truy vấn của bạn sau đó có thể được viết để tìm nạp 1 khóa trên cùng theo thứ tự được yêu cầu từ chế độ xem (lý tưởng nhất là vớiNOEXPAND ), sau đó nối lại các bảng cơ sở để tìm nạp bất kỳ cột nào còn lại bằng cách sử dụng các phím từ chế độ xem.

Một biến thể khác là phân cụm khung nhìn trên các cột thứ tự và các phím của bảng, sau đó viết truy vấn để tìm nạp thủ công các cột không xem từ bảng cơ sở bằng các phím. Tùy chọn tốt nhất cho bạn phụ thuộc vào bối cảnh rộng hơn. Một cách tốt để quyết định là kiểm tra nó với dữ liệu thực và khối lượng công việc.

Giải pháp cơ bản

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;

Kế hoạch thực hiện:

Chỉ số lực lượng vũ phu

Sử dụng một chỉ mục không bao gồm

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

Kế hoạch thực hiện:

Chỉ mục không bao gồm để đặt hàng

Có một tra cứu trong kế hoạch này, nhưng nó chỉ được sử dụng để tìm nạp một hàng duy nhất.

Chế độ xem chỉ mục tối thiểu

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

Truy vấn:

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;

Kế hoạch thực hiện:

Kế hoạch truy vấn cuối cùng

Điều này cho thấy các khóa bảng được lấy (một hàng tìm nạp từ chỉ mục được nhóm theo thứ tự) theo sau là hai tra cứu hàng đơn trên các bảng cơ sở để tìm nạp các cột còn lại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.