Saya punya meja dengan beberapa baris. Setup yang disederhanakan mengikuti
CREATE TABLE #data ([Id] int, [Status] int);
INSERT INTO #data
VALUES (100, 1), (101, 2), (102, 3), (103, 2);
Dan saya punya kueri yang menggabungkan tabel ini ke satu set nilai tabel yang dibangun baris (terbuat dari variabel dan konstanta), seperti
DECLARE @id1 int = 101, @id2 int = 105;
SELECT
COALESCE(p.[Code], 'X') AS [Code],
COALESCE(d.[Status], 0) AS [Status]
FROM (VALUES
(@id1, 'A'),
(@id2, 'B')
) p([Id], [Code])
FULL JOIN #data d ON d.[Id] = p.[Id];
Rencana pelaksanaan kueri menunjukkan bahwa keputusan pengoptimal adalah menggunakan FULL LOOP JOIN
strategi, yang tampaknya tepat, karena kedua input memiliki sangat sedikit baris. Satu hal yang saya perhatikan (dan tidak bisa setuju), adalah baris TVC sedang digulung (lihat area rencana eksekusi di kotak merah).
Mengapa optimizer memperkenalkan spool di sini, apa alasan untuk melakukannya? Tidak ada yang kompleks di luar gulungan. Sepertinya itu tidak perlu. Bagaimana cara menghilangkannya dalam hal ini, apa saja cara yang mungkin?
Rencana di atas diperoleh pada
Microsoft SQL Server 2014 (SP2-CU11) (KB4077063) - 12.0.5579.0 (X64)
sumber
Jawaban:
Hal di luar spool bukanlah referensi tabel sederhana, yang dapat dengan mudah diduplikasi ketika alternatif join / anti semi join dihasilkan.
Mungkin terlihat sedikit seperti tabel (Pemindaian Konstan) tetapi untuk pengoptimal * ini adalah
UNION ALL
baris terpisah dalamVALUES
klausa.Kompleksitas tambahan sudah cukup bagi pengoptimal untuk memilih spool dan memutar ulang baris sumber, dan tidak mengganti spool dengan "tabel get" sederhana nanti. Misalnya, transformasi awal dari gabungan penuh terlihat seperti ini:
Perhatikan gulungan ekstra yang diperkenalkan oleh transformasi umum. Gulungan di atas meja sederhana dibersihkan kemudian oleh aturan
SpoolGetToGet
.Jika pengoptimal memiliki
SpoolConstGetToConstGet
aturan yang sesuai , prinsipnya bisa berfungsi sesuai keinginan.Gunakan tabel nyata (sementara atau variabel), atau tulis transformasi dari gabungan lengkap secara manual, misalnya:
Rencanakan penulisan ulang manual:
Ini memiliki perkiraan biaya 0,0067201 unit, dibandingkan dengan 0,0203412 unit untuk aslinya.
* Dapat diamati sebagai
LogOp_UnionAll
dalam Pohon Konversi (TF 8605). Di Pohon Input (TF 8606) itu adalah aLogOp_ConstTableGet
. The Dikonversi Pohon menunjukkan pohon elemen ekspresi optimizer setelah parsing, normalisasi, algebrization, mengikat, dan beberapa persiapan lainnya. The Masukan Pohon menunjukkan unsur-unsur setelah konversi ke Negasi Bentuk Normal (NNF convert), runtime konstan runtuh, dan beberapa lainnya bit dan bobs. Konversi NNF mencakup logika untuk menutup persatuan logis dan tabel umum, antara lain.sumber
Spool tabel hanya membuat tabel dari dua set tupel yang ada dalam
VALUES
klausa.Anda bisa menghilangkan spool dengan memasukkan nilai-nilai tersebut ke tabel temp terlebih dahulu, seperti:
Melihat rencana eksekusi untuk permintaan Anda, kami melihat daftar output berisi dua kolom yang menggunakan
Union
awalan; ini adalah petunjuk bahwa spool membuat tabel dari sumber union'd:Itu
FULL OUTER JOIN
membutuhkan SQL Server untuk mengakses nilai dalamp
dua kali, sekali untuk setiap "sisi" dari bergabung. Membuat spul memungkinkan loop batin yang dihasilkan bergabung untuk mengakses data spool.Menariknya, jika Anda mengganti
FULL OUTER JOIN
dengan aLEFT JOIN
dan aRIGHT JOIN
, danUNION
hasilnya bersama-sama, SQL Server tidak menggunakan spool.Catatan, saya tidak menyarankan menggunakan
UNION
kueri di atas; untuk set input yang lebih besar, itu mungkin tidak lebih efisien daripada yang sederhanaFULL OUTER JOIN
yang sudah Anda miliki.sumber