Cari dan Anda harus Memindai ... pada tabel dipartisi


22

Saya sudah membaca artikel ini di PCMag oleh Itzik Ben-Gan :

Carilah dan Anda Harus Memindai Bagian I: Ketika Pengoptimal Tidak Mengoptimalkan
Mencari dan Anda Akan Memindai Bagian II: Tombol Meningkat

Saat ini saya mengalami masalah "Grup Dikelompokkan" dengan semua tabel yang dipartisi. Kami menggunakan trik yang disediakan oleh Itzik Ben-Gan untuk mendapatkan maks (ID), tetapi terkadang itu tidak berjalan:

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 

Saya mendapatkan rencana ini

masukkan deskripsi gambar di sini

Tetapi setelah 45 menit, lihat bacaannya

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

bahwa saya keluar dari sp_whoisactive.

Biasanya berjalan cukup cepat, tetapi tidak hari ini.

Sunting: struktur tabel dengan partisi:

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

Jawaban:


28

Masalah dasar adalah bahwa Indeks Pencarian tidak diikuti oleh operator Top. Ini adalah optimasi yang biasanya diperkenalkan ketika pencarian mengembalikan baris dalam urutan yang benar untuk MIN\MAXagregat.

Optimasi ini mengeksploitasi fakta bahwa baris min / maks adalah yang pertama dalam urutan naik atau turun. Mungkin juga bahwa pengoptimal tidak dapat menerapkan pengoptimalan ini ke tabel yang dipartisi; Saya lupa.

Pokoknya, intinya adalah bahwa tanpa transformasi ini, rencana eksekusi berakhir memproses setiap baris yang memenuhi syarat S.UpdatedID <= @IDColumnThresholdValueper partisi, daripada satu baris yang diinginkan per partisi.

Anda belum memberikan definisi tabel, indeks, atau partisi di pertanyaan jadi saya tidak bisa lebih spesifik. Anda harus memeriksa bahwa indeks Anda akan mendukung transformasi semacam itu. Kurang lebih setara, Anda juga bisa mengekspresikan MAXsebagai TOP (1) ... ORDER BY UpdatedID DESC.

Jika ini menghasilkan Sort (termasuk Sort TopN ), Anda tahu indeks Anda tidak membantu. Sebagai contoh:

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;

Bentuk rencana yang harus dihasilkan ini adalah:

Bentuk rencana yang diinginkan

Perhatikan Top di bawah Index Seek. Ini membatasi pemrosesan hingga satu baris per partisi.

Atau, menggunakan tabel sementara untuk menyimpan nomor partisi:

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;

Catatan: mengakses tabel sistem dalam kueri Anda mencegah paralelisme. Jika ini penting, pertimbangkan mematerialisasi nomor partisi dalam tabel sementara, lalu APPLYdari itu. Paralelisme biasanya tidak membantu dalam pola ini (dengan pengindeksan yang benar) tetapi akan lalai saya untuk tidak menyebutkannya.

Catatan sisi 2: Ada item Connect aktif yang meminta dukungan MIN\MAXbawaan untuk agregat dan Top pada objek yang dipartisi.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.