แสวงหาและคุณจะสแกน ... บนตารางที่แบ่งพาร์ติชัน


22

ฉันได้อ่านบทความเหล่านี้ใน PCMag โดยItzik Ben-Gan :

แสวงหาและคุณจะสแกนส่วนที่ 1: เมื่อเครื่องมือเพิ่มประสิทธิภาพไม่ได้ปรับให้เหมาะสม
แสวงหาและคุณจะสแกนส่วนที่สอง: คีย์จากน้อยไปมาก

ขณะนี้ฉันมีปัญหา "Grouped Max" กับตารางที่แบ่งพาร์ติชันทั้งหมดของเรา เราใช้เคล็ดลับ Itzik Ben-Gan ที่ให้ไว้เพื่อรับ max (ID) แต่บางครั้งก็ไม่ได้ทำงาน:

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 

ฉันได้รับแผนนี้

ป้อนคำอธิบายรูปภาพที่นี่

แต่หลังจากผ่านไป 45 นาทีให้ดูที่การอ่าน

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

ที่ฉันออกsp_whoisactiveไป

ปกติแล้วมันจะทำงานค่อนข้างเร็ว แต่ไม่ใช่ในวันนี้

แก้ไข: โครงสร้างตารางที่มีพาร์ทิชัน:

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

คำตอบ:


28

ปัญหาพื้นฐานคือดัชนีค้นหาไม่ได้ตามด้วยตัวดำเนินการยอดนิยม นี่คือการปรับให้เหมาะสมที่มักจะแนะนำเมื่อการค้นหาส่งคืนแถวในลำดับที่ถูกต้องสำหรับการMIN\MAXรวม

การปรับให้เหมาะสมนี้ใช้ประโยชน์จากข้อเท็จจริงที่ว่าแถว min / max เป็นแถวแรกในลำดับจากน้อยไปมากหรือมากไปหาน้อย อาจเป็นไปได้ว่าเครื่องมือเพิ่มประสิทธิภาพไม่สามารถใช้การเพิ่มประสิทธิภาพนี้กับตารางที่แบ่งพาร์ติชันได้ ฉันลืม.

อย่างไรก็ตามประเด็นก็คือหากไม่มีการแปลงนี้แผนดำเนินการจะสิ้นสุดการประมวลผลทุกแถวที่มีคุณสมบัติเหมาะสมS.UpdatedID <= @IDColumnThresholdValueสำหรับแต่ละพาร์ติชันแทนที่จะเป็นหนึ่งแถวที่ต้องการต่อพาร์ติชัน

คุณยังไม่ได้ให้คำจำกัดความของตารางดัชนีหรือการแบ่งพาร์ติชันในคำถามดังนั้นฉันจึงไม่เจาะจงมากขึ้น คุณควรตรวจสอบว่าดัชนีของคุณสนับสนุนการเปลี่ยนแปลงดังกล่าวหรือไม่ มากหรือน้อยเท่ากันคุณยังสามารถแสดงความเป็นMAXTOP (1) ... ORDER BY UpdatedID DESC

หากผลลัพธ์ในการเรียงลำดับ (รวมถึงการเรียงลำดับ TopN ) คุณรู้ว่าดัชนีของคุณไม่มีประโยชน์ ตัวอย่างเช่น:

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;

รูปร่างของแผนที่ควรสร้างคือ:

รูปร่างของแผนที่ต้องการ

แจ้งให้ทราบด้านบนด้านล่างดัชนีค้นหา สิ่งนี้ จำกัด การประมวลผลที่หนึ่งแถวต่อพาร์ติชัน

หรือใช้ตารางชั่วคราวเพื่อเก็บหมายเลขพาร์ติชัน:

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;

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

หมายเหตุด้าน 2: มีรายการเชื่อมต่อที่ใช้งานอยู่ซึ่งร้องขอการสนับสนุนในMIN\MAXตัวสำหรับการรวมและบนสุดบนวัตถุที่แบ่งพาร์ติชัน

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