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 Spooloperatö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 Spooloperatö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 Spooliş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 JOINSQL 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 Joiniçin Row Count Spool1 satıra 10.000 satır aşağı süzer. Bu nedenle, bir LOOP JOINsonraki 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 SpoolHerhangi 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 Spooltahmini 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






