Saya memiliki kueri yang berjalan dalam 800 milidetik di SQL Server 2012 dan membutuhkan waktu sekitar 170 detik di SQL Server 2014 . Saya pikir saya mempersempit ini ke perkiraan kardinalitas yang buruk untuk Row Count Spool
operator. Saya sudah membaca sedikit tentang operator spool (misalnya, di sini dan di sini ), tetapi saya masih mengalami kesulitan memahami beberapa hal:
- Mengapa kueri ini membutuhkan
Row Count Spool
operator? Saya pikir itu tidak perlu untuk pembenaran, jadi pengoptimalan spesifik apa yang ingin disediakannya? - Mengapa SQL Server memperkirakan bahwa gabungan ke
Row Count Spool
operator menghapus semua baris? - Apakah ini bug di SQL Server 2014? Jika demikian, saya akan mengajukan di Connect. Tapi saya ingin pemahaman yang lebih dalam dulu.
Catatan: Saya dapat menulis ulang kueri sebagai LEFT JOIN
atau menambahkan indeks ke tabel untuk mencapai kinerja yang dapat diterima di SQL Server 2012 dan SQL Server 2014. Jadi pertanyaan ini lebih lanjut tentang memahami kueri khusus ini dan merencanakannya secara mendalam dan lebih sedikit tentang cara mengucapkan kueri secara berbeda.
Permintaan lambat
Lihat Pastebin ini untuk skrip pengujian lengkap. Berikut adalah kueri pengujian khusus yang saya lihat:
-- 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: Perkiraan rencana kueri
SQL Server percaya bahwa Left Anti Semi Join
untuk Row Count Spool
akan menyaring 10.000 baris ke 1 baris. Karena alasan ini, ia memilih a LOOP JOIN
untuk gabungan selanjutnya #existingCustomers
.
SQL Server 2014: Paket kueri yang sebenarnya
Seperti yang diharapkan (oleh semua orang kecuali SQL Server!), Row Count Spool
Tidak menghapus baris apa pun. Jadi kita mengulang 10.000 kali ketika SQL Server diharapkan untuk mengulang hanya sekali.
SQL Server 2012: Perkiraan rencana kueri
Saat menggunakan SQL Server 2012 (atau OPTION (QUERYTRACEON 9481)
dalam SQL Server 2014), Row Count Spool
tidak mengurangi # estimasi baris dan hash bergabung dipilih, menghasilkan rencana yang jauh lebih baik.
LEFT JOIN menulis ulang
Untuk referensi, berikut adalah cara saya dapat menulis ulang kueri untuk mencapai kinerja yang baik di semua SQL Server 2012, 2014, dan 2016. Namun, saya masih tertarik pada perilaku spesifik kueri di atas dan apakah itu adalah bug dalam Pengestimasi Kardinalitas SQL Server 2014 yang baru.
-- 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
sumber