Ara ve Tara… Bölünmüş masalarda


22

Bu makaleleri PCMag'da Itzik Ben-Gan tarafından okudum :

Birinci Bölümde Arayın ve Taranacaksınız: Optimize Edici Aramaya Optimize
Etmediğinde ve Bölüm II'yi Tararken: Artan Anahtarlar

Şu anda bölümlenmiş tüm tablolarımızda "Gruplanmış Maks." Sorunu yaşıyorum. Max (ID) almak için verilen Itzik Ben-Gan hilesini kullanıyoruz , ancak bazen çalışmıyor:

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 

Bu planı alıyorum

görüntü tanımını buraya girin

Fakat 45 dakika sonra, okumalara bakın

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

Çıktım ki sp_whoisactive.

Normalde oldukça hızlı çalışır, ancak bugün değil.

Düzenleme: bölümleri ile tablo yapısı:

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

Yanıtlar:


28

Temel sorun, Endeks Aramanın bir En İyi operatör tarafından takip edilmemesidir. Bu, genellikle, arama bir MIN\MAXtoplam için doğru sıradaki satırları döndürdüğünde ortaya çıkan bir optimizasyondur .

Bu optimizasyon, min / max satırının artan veya azalan sırada ilk sırada olması gerçeğinden faydalanır. Ayrıca, optimize edicinin bu optimizasyonu bölümlenmiş tablolara uygulayamaması da olabilir; Unuttum.

Her neyse, mesele, bu dönüşüm olmadan, yürütme planının S.UpdatedID <= @IDColumnThresholdValue, bölüm başına istenen bir satır yerine, her bölüm için geçerli olan her satırın işlenmesinin sona ermesidir.

Soruda tablo, dizin veya bölümleme tanımları girmediniz, bu yüzden daha fazla spesifik olamam. Dizininizin böyle bir dönüşümü destekleyip desteklemediğini kontrol etmelisiniz. Daha fazla veya daha az eşdeğer, ayrıca MAXolarak da ifade edebilirsiniz TOP (1) ... ORDER BY UpdatedID DESC.

Bu bir Sıralamada ( TopN Sıralama dahil ) sonuçlanırsa , dizininizin yardımcı olmadığını biliyorsunuzdur. Örneğin:

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;

Bunun üretmesi gereken plan şekli:

İstenilen plan şekli

Dizin Aramanın altındaki Top dikkat edin. Bu, işlemeyi bölüm başına bir satırla sınırlandırır.

Veya, bölüm numaralarını tutmak için geçici bir tablo kullanarak:

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;

Not: Sorgunuzdaki bir sistem tablosuna erişmek, paralelliği önler. Bu önemliyse, bölüm numaralarını geçici bir tabloda, daha sonra onlardan oluşturmayı düşünün APPLY. Paralelcilik normalde bu düzende yardımcı olmaz (doğru indeksleme ile), fakat benim söylememem bana yardımcı olur.

Yan not 2: Toplamalar ve bölümlenmiş nesnelerde üst kısımlar için yerleşik destek isteyen aktif bir Bağlan öğesi varMIN\MAX .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.