TL; DR
Karena pertanyaan ini terus mendapatkan pandangan, saya akan meringkasnya di sini sehingga pendatang baru tidak harus menderita sejarah:
JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1, @value2) -- this is blazing fast
-- Note that here if @value1 has a value, @value2 is NULL, and vice versa
Saya menyadari ini mungkin bukan masalah semua orang, tetapi dengan menyoroti sensitivitas klausa ON, ini mungkin membantu Anda melihat ke arah yang benar. Bagaimanapun teks asli ada di sini untuk antropolog masa depan:
Teks asli
Pertimbangkan permintaan sederhana berikut (hanya 3 tabel yang terlibat)
SELECT
l.sku_id AS ProductId,
l.is_primary AS IsPrimary,
v1.category_name AS Category1,
v2.category_name AS Category2,
v3.category_name AS Category3,
v4.category_name AS Category4,
v5.category_name AS Category5
FROM category c4
JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'
JOIN category c3 ON c3.category_id = c4.parent_category_id
JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'
JOIN category c2 ON c2.category_id = c3.category_id
JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'
JOIN category c1 ON c1.category_id = c2.parent_category_id
JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'
LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang
JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
l.category_id = c4.category_id OR
l.category_id = c5.category_id
)
WHERE c4.[level] = 4 AND c4.version_id = 5
Ini adalah permintaan yang cukup sederhana, satu-satunya bagian yang membingungkan adalah gabungan kategori terakhir, ini cara ini karena kategori level 5 mungkin atau mungkin tidak ada. Di akhir kueri saya mencari info kategori per ID produk (SKU ID), dan di situlah tabel_link yang sangat besar masuk. Akhirnya, tabel #Ids hanyalah tabel temp yang berisi 10'000 Id.
Ketika dieksekusi, saya mendapatkan rencana eksekusi aktual berikut:
Seperti yang Anda lihat, hampir 90% dari waktu dihabiskan di Nested Loops (Inner Join). Berikut informasi tambahan tentang Nested Loops tersebut:
Perhatikan bahwa nama tabel tidak sama persis karena saya mengedit nama tabel kueri agar mudah dibaca, tetapi cukup mudah untuk mencocokkan (ads_alt_category = kategori). Apakah ada cara untuk mengoptimalkan permintaan ini? Juga perhatikan bahwa dalam produksi, tabel temp #Ids tidak ada, itu adalah Parameter yang Dihitung Tabel dari 10'000 Id yang sama diteruskan ke Prosedur Tersimpan.
Informasi tambahan:
- indeks kategori pada category_id dan parent_category_id
- indeks category_voc pada category_id, language_code
- indeks category_link di sku_id, category_id
Edit (dipecahkan)
Seperti yang ditunjukkan oleh jawaban yang diterima, masalahnya adalah klausa OR di category_link BERGABUNG. Namun, kode yang disarankan dalam jawaban yang diterima sangat lambat, bahkan lebih lambat dari kode aslinya. Solusi yang jauh lebih cepat dan juga lebih bersih adalah dengan mengganti kondisi JOIN saat ini dengan yang berikut:
JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id, c4.category_id)
Tweak menit ini adalah solusi tercepat, diuji terhadap gabungan ganda dari jawaban yang diterima dan juga diuji terhadap CROSS BERLAKU seperti yang disarankan oleh valverij.