Salah satu pendekatan mungkin menggunakan tabel #temp untuk nilai-nilai dan juga memperkenalkan kolom equijoin dummy untuk memungkinkan hash bergabung. Sebagai contoh:
-- 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
Rencana kinerja dan kueri
Pendekatan ini menghasilkan rencana kueri seperti berikut, dan pencocokan hash dilakukan dalam mode batch:
Jika saya mengganti SELECT
pernyataan dengan SUM
satu CASE
pernyataan untuk menghindari harus melakukan streaming semua baris yang ke konsol dan kemudian menjalankan query pada 100mm nyata baris tabel columnstore saya telah tergeletak di sekitar, saya melihat kinerja yang cukup baik untuk menghasilkan 300MM diperlukan baris:
CPU time = 33803 ms, elapsed time = 4363 ms.
Dan rencana aktual menunjukkan paralelisasi yang baik dari hash join
Catatan tentang hash bergabung dengan paralelisasi ketika semua baris memiliki nilai yang sama
Kinerja kueri ini sangat bergantung pada setiap utas di sisi probe join yang memiliki akses ke tabel hash lengkap (sebagai lawan dari versi hash yang dipartisi, yang akan memetakan semua baris ke utas tunggal mengingat hanya ada satu nilai berbeda untuk dummy
kolom).
Untungnya, ini benar dalam kasus ini (seperti yang dapat kita lihat dengan kurangnya Parallelism
operator di sisi probe) dan seharusnya benar karena mode batch membangun tabel hash tunggal yang dibagi di seluruh thread. Oleh karena itu, setiap utas dapat mengambil baris mereka dari Columnstore Index Scan
dan mencocokkannya dengan tabel hash bersama itu. Dalam SQL Server 2012, fungsi ini jauh lebih mudah diprediksi karena tumpahan menyebabkan operator memulai kembali dalam mode Row, keduanya kehilangan manfaat dari mode batch dan juga membutuhkan Repartition Streams
operator di sisi probe bergabung yang akan menyebabkan kemiringan benang dalam kasus ini . Mengizinkan tumpahan tetap dalam mode batch adalah peningkatan besar dalam SQL Server 2014.
Setahu saya, mode baris tidak memiliki kemampuan tabel hash bersama ini. Namun, dalam beberapa kasus, biasanya dengan perkiraan kurang dari 100 baris di sisi build, SQL Server akan membuat salinan terpisah dari tabel hash untuk setiap utas (dapat diidentifikasi oleh Distribute Streams
pemimpin ke dalam gabungan hash). Ini bisa sangat kuat, tetapi jauh lebih tidak dapat diandalkan daripada mode batch karena itu tergantung pada perkiraan kardinalitas Anda dan SQL Server sedang mencoba untuk mengevaluasi manfaat versus biaya membangun salinan penuh tabel hash untuk setiap utas.
UNION ALL: alternatif yang lebih sederhana
Paul White menunjukkan bahwa opsi lain, dan mungkin lebih sederhana, akan digunakan UNION ALL
untuk menggabungkan baris untuk setiap nilai. Ini kemungkinan adalah taruhan terbaik Anda dengan asumsi bahwa mudah bagi Anda untuk membangun SQL ini secara dinamis. Sebagai contoh:
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
Ini juga menghasilkan rencana yang dapat memanfaatkan mode batch dan memberikan kinerja yang lebih baik daripada jawaban aslinya. (Meskipun dalam kedua kasus kinerjanya cukup cepat sehingga setiap pemilihan atau penulisan data ke meja dengan cepat menjadi hambatan.) UNION ALL
Pendekatan ini juga menghindari bermain game seperti mengalikan dengan 0. Terkadang lebih baik berpikir sederhana!
CPU time = 8673 ms, elapsed time = 4270 ms.