วิธีการใช้ประโยชน์จากโหมดแบทช์ด้วย UNPIVOT (การเข้าร่วมแบบวนซ้ำ)


12

ฉันมีแบบสอบถามของแบบฟอร์มต่อไปนี้:

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

การดำเนินการนี้จะใช้ทุกแถวจากแบบสอบถามย่อยที่สำรองไว้ในคอลัมน์ ( ColumnstoreTable) และคูณแถวเหล่านั้น UNPIVOTนี้เป็นหลัก แบบสอบถามจริงมีขนาดใหญ่กว่านี้ ส่วนนี้ของแบบสอบถามจะดึงข้อมูลไปยังการประมวลผลอื่น ๆ

ปัญหาที่นี่คือสิ่งนี้CROSS APPLYถูกนำไปใช้เป็นการเข้าร่วมแบบวนรอบซึ่งเป็นตัวเลือกที่สมเหตุสมผล น่าเสียดายที่การรวมลูปไม่สนับสนุนโหมดแบทช์

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

ฉันจะเขียนแบบสอบถามนี้ใหม่เพื่อที่ฉันจะไม่เปลี่ยนจากโหมดแบทช์ได้อย่างไร

ฉันลองใช้ตารางชั่วคราวแทนVALUESแต่นั่นไม่ได้เปลี่ยนความจริงที่ว่าไม่มีเงื่อนไขการเข้าร่วมที่เท่าเทียมกันในการเข้าร่วมแฮช

คำตอบ:


12

วิธีการหนึ่งอาจใช้ตาราง #temp สำหรับค่าต่างๆและยังแนะนำคอลัมน์คอลัมน์รูปหุ่นเพื่ออนุญาตให้เข้าร่วมแฮช ตัวอย่างเช่น:

-- 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

แผนประสิทธิภาพและแบบสอบถาม

วิธีการนี้ให้ผลแบบสอบถามแผนดังต่อไปนี้และทำการแฮชตรงกันในโหมดแบทช์:

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

ถ้าฉันแทนที่SELECTคำสั่งด้วย a SUMของCASEคำสั่งเพื่อหลีกเลี่ยงการสตรีมแถวเหล่านั้นทั้งหมดไปยังคอนโซลและจากนั้นเรียกใช้แบบสอบถามบนตารางคอลัมน์แถวแถว 100 มม. จริงที่ฉันโกหกฉันเห็นประสิทธิภาพที่ค่อนข้างดีในการสร้างสิ่งที่จำเป็น 300MM แถว:

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

และแผนจริงแสดงให้เห็นถึงการขนานที่ดีของการเข้าร่วมแฮ

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

หมายเหตุเกี่ยวกับการแฮชการรวมขนานเมื่อแถวทั้งหมดมีค่าเท่ากัน

ประสิทธิภาพการทำงานของแบบสอบถามนี้ขึ้นอยู่กับแต่ละเธรดที่ด้านโพรบของการเข้าร่วมที่มีการเข้าถึงตารางแฮชแบบเต็มรูปแบบ (ซึ่งตรงกันข้ามกับเวอร์ชันที่แบ่งพาร์ติชันแฮชซึ่งจะจับคู่แถวทั้งหมดกับเธรดเดี่ยว สำหรับdummyคอลัมน์)

โชคดีที่มันเป็นจริงในกรณีนี้ (อย่างที่เราเห็นได้จากการขาดตัวParallelismดำเนินการด้านโพรบ) และน่าเชื่อถืออย่างแท้จริงเพราะโหมดแบตช์สร้างตารางแฮชเดี่ยวที่แชร์ข้ามเธรด ดังนั้นแต่ละเธรดสามารถนำแถวจากColumnstore Index Scanและจับคู่กับตารางแฮชที่แชร์ ใน SQL Server 2012 ฟังก์ชันการทำงานนี้สามารถคาดการณ์ได้น้อยกว่ามากเนื่องจากการรั่วไหลทำให้ตัวดำเนินการเริ่มต้นใหม่ในโหมดแถวทั้งสูญเสียผลประโยชน์ของโหมดแบตช์และยังต้องการตัวRepartition Streamsดำเนินการในด้านโพรบของการเข้าร่วมซึ่งจะทำให้ . การอนุญาตให้มีการรั่วไหลในโหมดแบตช์เป็นการปรับปรุงที่สำคัญใน SQL Server 2014

สำหรับความรู้ของฉันโหมดแถวไม่ได้มีความสามารถในตารางแฮชที่ใช้ร่วมกันนี้ อย่างไรก็ตามในบางกรณีโดยทั่วไปแล้วมีการประมาณน้อยกว่า 100 แถวในด้านการสร้าง SQL Server จะสร้างสำเนาของตารางแฮชแยกต่างหากสำหรับแต่ละเธรด (สามารถระบุได้โดยDistribute Streamsการนำเข้าสู่การแฮช) สิ่งนี้มีประสิทธิภาพมาก แต่มีความน่าเชื่อถือน้อยกว่าโหมดแบตช์เนื่องจากขึ้นอยู่กับการประเมินความสำคัญของคุณและ SQL Server พยายามประเมินผลประโยชน์เทียบกับค่าใช้จ่ายในการสร้างสำเนาตารางแฮชแบบเต็มสำหรับแต่ละเธรด

ยูเนี่ยนทั้งหมด: ทางเลือกที่ง่ายกว่า

Paul White ชี้ให้เห็นว่าตัวเลือกอื่นและอาจง่ายกว่านั้นคือใช้UNION ALLเพื่อรวมแถวสำหรับแต่ละค่า นี่น่าจะเป็นทางออกที่ดีที่สุดของคุณโดยสมมติว่าคุณสามารถสร้าง SQL นี้แบบไดนามิกได้ง่าย ตัวอย่างเช่น:

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

สิ่งนี้ยังให้แผนที่สามารถใช้โหมดแบทช์และให้ประสิทธิภาพที่ดียิ่งขึ้นกว่าคำตอบเดิม (แม้ว่าในทั้งสองกรณีประสิทธิภาพจะเร็วพอที่การเลือกหรือเขียนข้อมูลลงในตารางจะกลายเป็นคอขวดอย่างรวดเร็ว) UNION ALLวิธีการนี้ยังช่วยหลีกเลี่ยงการเล่นเกมเช่นการคูณด้วย 0 บางครั้งก็เป็นการง่ายที่จะคิด!

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

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


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