Bir UNPIVOT (döngü birleştirme) ile Toplu Mod nasıl kullanılır?


12

Aşağıdaki formda bir sorgu var:

SELECT ...
FROM ColumnstoreTable cs
CROSS APPLY (
    SELECT *
    FROM (VALUES
        ('A', cs.DataA)
        , ('B', cs.DataB)
        , ('C', cs.DataC)
    ) x(Col0, Col1)
) someValues

Bu, her satırı bir Columnstore destekli alt sorgudan ( ColumnstoreTable) alır ve bu satırları çarpar. Bu aslında bir UNPIVOT. Gerçek sorgu bundan daha büyük. Sorgunun bu bölümü diğer işleme beslenir.

Buradaki sorun CROSS APPLY, bunun makul bir seçim olan bir döngü birleşimi olarak uygulanmasıdır. Maalesef, döngü birleşimleri toplu modu desteklemiyor.

Sorgunun bu bölümü çok performans açısından önemlidir ve toplu modda çalıştırmanın performans için çok yararlı olabileceğinden şüpheleniyorum.

Toplu moddan geçiş yapmamak için bu sorguyu nasıl yeniden yazabilirim?

Bunun yerine geçici bir tablo kullanmayı denedim VALUES, ancak bu karma birleştirmek için eşitlik birleştirme koşulu olmadığı gerçeğini değiştirmedi.

Yanıtlar:


12

Bir yaklaşım, değerler için #temp tablosu kullanmak ve ayrıca karma birleştirmeye izin vermek için bir kukla equijoin sütunu kullanmak olabilir. Örneğin:

-- Create a #temp table with a dummy column to match the hash join
-- and the actual column you want
CREATE TABLE #values (dummy INT NOT NULL, Col0 CHAR(1) NOT NULL)
INSERT INTO #values (dummy, Col0)
VALUES (0, 'A'),
        (0, 'B'),
        (0, 'C')
GO

-- A similar query, but with a dummy equijoin condition to allow for a hash join
SELECT v.Col0, 
    CASE v.Col0 
        WHEN 'A' THEN cs.DataA 
        WHEN 'B' THEN cs.DataB 
        WHEN 'C' THEN cs.DataC
        END AS Col1
FROM ColumnstoreTable cs
JOIN #values v
    -- Join your dummy column to any numeric column on the columnstore,
    -- multiplying that column by 0 to ensure a match to all #values
    ON v.dummy = cs.DataA * 0

Performans ve sorgu planı

Bu yaklaşım aşağıdaki gibi bir sorgu planı verir ve karma eşleme toplu modda gerçekleştirilir:

resim açıklamasını buraya girin

Tüm bu satırları konsola akıtmaktan ve ardından sorguyu etrafta bulunduğum gerçek bir 100MM satır sütun mağaza tablosunda çalıştırmak zorunda kalmamak için ifadeyi SELECTbir ifadeyle değiştirirsem , gerekli 300MM'yi oluşturmak için oldukça iyi bir performans görüyorum satırlar:SUMCASE

CPU time = 33803 ms, elapsed time = 4363 ms.

Ve gerçek plan, karma birleştirmenin iyi paralelliğini gösterir.

resim açıklamasını buraya girin

Tüm satırlar aynı değere sahip olduğunda karma birleştirme paralelleştirmesi hakkında notlar

Bu sorgunun performansı, birleştirme işleminin prob tarafındaki her bir iş parçacığına tam karma tabloya erişime (her bir satırın tek bir iş parçacığıyla eşleşeceği karma bölümlü bir sürümün aksine) büyük ölçüde bağlıdır. için dummykolon).

Neyse ki, bu durumda ( Parallelismprob tarafında bir operatörün eksikliğinden görebildiğimiz gibi ) doğrudur ve güvenilir bir şekilde doğru olmalıdır çünkü toplu mod, iş parçacıkları arasında paylaşılan tek bir karma tablo oluşturur. Bu nedenle, her iş parçacığı satırlarını alabilir Columnstore Index Scanve bunları paylaşılan karma tabloyla eşleştirebilir. SQL Server 2012'de bu işlevsellik çok daha az tahmin edilebilirdi, çünkü bir dökülme operatörün Satır modunda yeniden başlatılmasına neden oldu, hem toplu modun faydasını kaybetti hem Repartition Streamsde birleşimin prob tarafında bir operatör gerektirdiğinden bu durumda iplik eğrilmesine neden oldu . Dökülmelerin toplu modda kalmasına izin vermek SQL Server 2014'teki önemli bir gelişmedir.

Bildiğim kadarıyla, satır modu bu paylaşılan karma tablo yeteneğine sahip değil. Bununla birlikte, bazı durumlarda, tipik olarak oluşturma tarafında 100'den az satır tahminiyle SQL Server, her iş parçacığı için karma tablonun ayrı bir kopyasını oluşturur ( Distribute Streamskarma birleştirmeye giden satır tarafından tanımlanabilir ). Bu çok güçlü olabilir, ancak kardinalite tahminlerinize bağlı olduğundan ve SQL Server, her iş parçacığı için karma tablonun tam bir kopyasını oluşturma maliyetine karşı faydaları değerlendirmeye çalıştığı için toplu moddan çok daha az güvenilirdir.

BİRLİĞİ: daha basit bir alternatif

Paul White, UNION ALLher değer için satırları birleştirmek için başka ve potansiyel olarak daha basit bir seçeneğin kullanılacağına dikkat çekti . Bu SQL'i dinamik olarak oluşturmanın kolay olduğunu varsayarak muhtemelen en iyi bahistir. Örneğin:

SELECT 'A' AS Col0, c.DataA AS Col1
FROM ColumnstoreTable c
UNION ALL
SELECT 'B' AS Col0, c.DataB AS Col1
FROM ColumnstoreTable c
UNION ALL
SELECT 'C' AS Col0, c.DataC AS Col1
FROM ColumnstoreTable c

Bu aynı zamanda parti modunu kullanabilen ve orijinal yanıttan daha iyi performans sağlayan bir plan verir. (Her iki durumda da performans, herhangi bir veriyi seçip bir tabloya yazmanın hızla darboğaz haline gelmesine yetecek kadar hızlıdır.) UNION ALLYaklaşım aynı zamanda 0 ile çarpmak gibi oyunlar oynamaktan kaçınır. Bazen basit düşünmek en iyisidir!

CPU time = 8673 ms, elapsed time = 4270 ms.

resim açıklamasını buraya girin


BİRLİK TÜM hile bilmek iyidir, ancak kaynak sorgusu sadece bir tablo değil, kendi başına pahalı bir sorgu olması durumunda başarısız olur.
boot4life
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.