SQL Server 2012'de 800 milisaniyede çalışan ve SQL Server 2014'te yaklaşık 170 saniye süren bir sorgu var . Bunu Row Count Spool
operatör için kötü bir kardinalite tahminine daralttığımı düşünüyorum . Makara operatörleri hakkında biraz okudum (örneğin, burada ve burada ), ancak hala birkaç şeyi anlamada sorun yaşıyorum:
- Bu sorgu neden bir
Row Count Spool
operatöre ihtiyaç duyuyor ? Doğruluk için gerekli olduğunu düşünmüyorum, bu yüzden hangi spesifik optimizasyonu sağlamaya çalışıyor? - SQL Server neden
Row Count Spool
işleç birleştirmenin tüm satırları kaldırdığını tahmin ediyor ? - Bu SQL Server 2014'te bir hata mı? Öyleyse, Connect'te dosyalayacağım. Ama önce daha derin bir anlayış istiyorum.
Not: LEFT JOIN
SQL Server 2012 ve SQL Server 2014'te kabul edilebilir performans elde etmek için sorguyu bir olarak yeniden yazabilir veya tablolara dizinler ekleyebilirim. Yani bu soru bu özel sorguyu anlamak ve daha derinlemesine planlamakla ilgili ve daha az sorguyu farklı şekilde ifade etme.
Yavaş sorgu
Tam bir test komut dosyası için bu Pastebin'e bakın . İşte baktığım test sorgusu:
-- Prune any existing customers from the set of potential new customers
-- This query is much slower than expected in SQL Server 2014
SELECT *
FROM #potentialNewCustomers -- 10K rows
WHERE cust_nbr NOT IN (
SELECT cust_nbr
FROM #existingCustomers -- 1MM rows
)
SQL Server 2014: Tahmini sorgu planı
SQL Server inanmaktadır Left Anti Semi Join
için Row Count Spool
1 satıra 10.000 satır aşağı süzer. Bu nedenle, bir LOOP JOIN
sonraki birleşiminde a'yı seçer #existingCustomers
.
SQL Server 2014: Asıl sorgu planı
Beklendiği gibi (SQL Server hariç herkes tarafından!), Row Count Spool
Herhangi bir satır kaldırılmadı. SQL Server'ın yalnızca bir kez döngü yapması bekleniyorsa 10.000 kez döngü yapıyoruz.
SQL Server 2012: Tahmini sorgu planı
SQL Server 2012 kullanırken (veya OPTION (QUERYTRACEON 9481)
SQL Server 2014'te), Row Count Spool
tahmini satır sayısını azaltmaz ve bir karma birleşimi seçilir, bu da çok daha iyi bir planla sonuçlanır.
SOL BİRLEŞME yeniden yazma
Başvuru için, tüm SQL Server 2012, 2014 ve 2016'da iyi performans elde etmek için sorguyu yeniden yazabileceğim bir yol var. Ancak, yine de yukarıdaki sorgunun belirli davranışı ve bunun yeni SQL Server 2014 Kardinalite Tahmincisi'nde bir hatadır.
-- Re-writing with LEFT JOIN yields much better performance in 2012/2014/2016
SELECT n.*
FROM #potentialNewCustomers n
LEFT JOIN (SELECT 1 AS test, cust_nbr FROM #existingCustomers) c
ON c.cust_nbr = n.cust_nbr
WHERE c.test IS NULL