Tìm kiếm và bạn sẽ Quét trên các bảng được phân đoạn


22

Tôi đã đọc những bài viết này trên PCMag của Itzik Ben-Gan :

Tìm kiếm và bạn sẽ quét phần I: Khi trình tối ưu hóa không tối ưu hóa
tìm kiếm và bạn sẽ quét phần II: Phím tăng dần

Tôi hiện đang gặp sự cố "Nhóm tối đa" với tất cả các bảng được phân vùng của chúng tôi. Chúng tôi sử dụng thủ thuật mà Itzik Ben-Gan cung cấp để có được tối đa (ID), nhưng đôi khi nó không chạy:

DECLARE @MaxIDPartitionTable BIGINT
SELECT  @MaxIDPartitionTable = ISNULL(MAX(IDPartitionedTable), 0)
FROM    ( SELECT    *
          FROM      ( SELECT    partition_number PartitionNumber
                      FROM      sys.partitions
                      WHERE     object_id = OBJECT_ID('fct.MyTable')
                                AND index_id = 1
                    ) T1
                    CROSS APPLY ( SELECT    ISNULL(MAX(UpdatedID), 0) AS IDPartitionedTable
                                  FROM      fct.MyTable s
                                  WHERE     $PARTITION.PF_MyTable(s.PCTimeStamp) = PartitionNumber
                                            AND UpdatedID <= @IDColumnThresholdValue
                                ) AS o
        ) AS T2;
SELECT @MaxIDPartitionTable 

Tôi có kế hoạch này

nhập mô tả hình ảnh ở đây

Nhưng sau 45 phút, hãy nhìn vào bài đọc

reads          writes   physical_reads
12,949,127        2       12,992,610

mà tôi thoát khỏi sp_whoisactive.

Thông thường nó chạy khá nhanh, nhưng không phải hôm nay.

Chỉnh sửa: cấu trúc bảng với các phân vùng:

CREATE PARTITION FUNCTION [MonthlySmallDateTime](SmallDateTime) AS RANGE RIGHT FOR VALUES (N'2000-01-01T00:00:00.000', N'2000-02-01T00:00:00.000' /* and many more */)
go
CREATE PARTITION SCHEME PS_FctContractualAvailability AS PARTITION [MonthlySmallDateTime] TO ([Standard], [Standard])
GO
CREATE TABLE fct.MyTable(
    MyTableID BIGINT IDENTITY(1,1),
    [DT1TurbineID] INT NOT NULL,
    [PCTimeStamp] SMALLDATETIME NOT NULL,
    Filler CHAR(100) NOT NULL DEFAULT 'N/A',
    UpdatedID BIGINT NULL,
    UpdatedDate DATETIME NULL
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED 
(
    [DT1TurbineID] ASC,
    [PCTimeStamp] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = ROW) ON [PS_FctContractualAvailability]([PCTimeStamp])
) ON [PS_FctContractualAvailability]([PCTimeStamp])

GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_UpdatedID_PCTimeStamp] ON [fct].MyTable
(
    [UpdatedID] ASC,
    [PCTimeStamp] ASC
)
INCLUDE (   [UpdatedDate]) 
WHERE ([UpdatedID] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = ROW) ON [PS_FctContractualAvailability]([PCTimeStamp])
GO

Câu trả lời:


28

Vấn đề cơ bản là Index Seek không được theo dõi bởi một nhà điều hành hàng đầu. Đây là một tối ưu hóa thường được giới thiệu khi tìm kiếm trả về các hàng theo đúng thứ tự cho MIN\MAXtổng hợp.

Tối ưu hóa này khai thác thực tế rằng hàng tối thiểu / tối đa là hàng đầu tiên theo thứ tự tăng dần hoặc giảm dần. Cũng có thể là trình tối ưu hóa không thể áp dụng tối ưu hóa này cho các bảng được phân đoạn; Tôi quên mất.

Dù sao, vấn đề là không có sự chuyển đổi này, kế hoạch thực hiện sẽ xử lý mọi hàng đủ điều kiện S.UpdatedID <= @IDColumnThresholdValuecho mỗi phân vùng, thay vì một hàng mong muốn trên mỗi phân vùng.

Bạn chưa cung cấp bảng, chỉ mục hoặc định nghĩa phân vùng trong câu hỏi để tôi không thể cụ thể hơn nhiều. Bạn nên kiểm tra xem chỉ mục của bạn có hỗ trợ chuyển đổi như vậy không. Nhiều hơn hoặc ít hơn tương đương, bạn cũng có thể biểu thị MAXnhư một TOP (1) ... ORDER BY UpdatedID DESC.

Nếu điều này dẫn đến Sắp xếp (bao gồm Sắp xếp TopN ), bạn biết rằng chỉ mục của bạn không hữu ích. Ví dụ:

SELECT
    @MaxIDPartitionTable = ISNULL(MAX(T2.IDPartitionedTable), 0)
FROM    
( 
    SELECT
        O.IDPartitionedTable
    FROM      
    ( 
        SELECT
            P.partition_number AS PartitionNumber
        FROM sys.partitions AS P
        WHERE 
            P.[object_id] = OBJECT_ID(N'fct.MyTable', N'U')
            AND P.index_id = 1
    ) AS T1
    CROSS APPLY 
    (    
        SELECT TOP (1) 
            S.UpdatedID AS IDPartitionedTable
        FROM fct.MyTable AS S
        WHERE
            $PARTITION.PF_MyTable(S.PCTimeStamp) = T1.PartitionNumber
            AND S.UpdatedID <= @IDColumnThresholdValue
        ORDER BY
            S.UpdatedID DESC
    ) AS O
) AS T2;

Hình dạng kế hoạch này sẽ tạo ra là:

Hình dạng kế hoạch mong muốn

Lưu ý Top bên dưới Chỉ số Tìm kiếm. Điều này giới hạn việc xử lý một hàng trên mỗi phân vùng.

Hoặc, sử dụng bảng tạm thời để giữ số phân vùng:

CREATE TABLE #Partitions
(
    partition_number integer PRIMARY KEY CLUSTERED
);

INSERT #Partitions
    (partition_number)
SELECT
    P.partition_number AS PartitionNumber
FROM sys.partitions AS P
WHERE 
    P.[object_id] = OBJECT_ID(N'fct.MyTable', N'U')
    AND P.index_id = 1;

SELECT
    @MaxIDPartitionTable = ISNULL(MAX(T2.UpdatedID), 0)
FROM #Partitions AS P
CROSS APPLY 
(
    SELECT TOP (1) 
        S.UpdatedID
    FROM fct.MyTable AS S
    WHERE
        $PARTITION.PF_MyTable(S.PCTimeStamp) = P.partition_number
        AND S.UpdatedID <= @IDColumnThresholdValue
    ORDER BY
        S.UpdatedID DESC
) AS T2;

DROP TABLE #Partitions;

Lưu ý bên: truy cập một bảng hệ thống trong truy vấn của bạn ngăn chặn sự song song. Nếu điều này là quan trọng, hãy xem xét cụ thể hóa các số phân vùng trong một bảng tạm thời, sau đó APPLYtừ đó. Sự song song thường không hữu ích trong mô hình này (với việc lập chỉ mục chính xác) nhưng nó sẽ khiến tôi không đề cập đến nó.

Lưu ý bên 2: Có một mục Kết nối hoạt động yêu cầu hỗ trợ tích MIN\MAXhợp cho các tập hợp và Top trên các đối tượng được phân vùng.

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.