Saya memiliki masalah ini sejak lama, saya menemukan solusi yang cocok untuk saya dan melupakannya.
Tapi sekarang ada pertanyaan tentang SO jadi saya bersedia mengangkat masalah ini.
Ada tampilan yang menggabungkan beberapa tabel dengan cara yang sangat mudah (pesanan + garis pemesanan).
Ketika ditanya tanpa where
klausa, tampilan mengembalikan beberapa juta baris.
Namun, tidak ada yang pernah memanggilnya seperti itu. Permintaan yang biasa adalah
select * from that_nasty_view where order_number = 123456;
Ini mengembalikan sekitar 10 catatan dari 5m.
Suatu hal yang penting: tampilan berisi fungsi jendela rank()
,, yang dipartisi persis oleh bidang yang selalu digunakan tampilan:
rank() over (partition by order_number order by detail_line_number)
Sekarang, jika tampilan ini ditanya dengan parameter literal dalam string kueri, persis seperti yang ditunjukkan di atas, ia mengembalikan baris secara instan. Rencana eksekusi baik-baik saja:
- Pencarian indeks pada kedua tabel menggunakan indeks on
order_number
(menghasilkan 10 baris). - Menghitung jendela di atas hasil kecil yang dikembalikan.
- Memilih.
Namun, ketika tampilan dipanggil dengan cara parametrized, semuanya menjadi buruk:
Index scan
di semua tabel mengabaikan indeks. Mengembalikan baris 5m.- Bergabung besar.
- Menghitung windows di semua
partition
s (sekitar 500k windows). Filter
untuk mengambil 10 baris dari 5m.- Pilih
Ini terjadi dalam semua kasus ketika parameter terlibat. Itu bisa SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Itu bisa menjadi klien ODBC, seperti Excel:
select * from that_nasty_view where order_number = ?
Atau bisa juga klien lain yang menggunakan parameter dan bukan gabungan sql.
Jika fungsi jendela dihapus dari tampilan, itu berjalan dengan sangat cepat, terlepas dari apakah itu dipertanyakan dengan parameter atau tidak.
Solusi saya adalah menghapus fungsi yang menyinggung dan menerapkannya kembali pada tahap selanjutnya.
Tapi, apa yang terjadi? Apakah ini benar-benar bug dalam cara SQL Server 2008 menangani fungsi jendela?
order_number
bukan kunci utama. Itu int not null
dengan indeks nonclustered di kedua tabel.
OPTION (RECOMPILE)
bantuan?