Rekan MVP Jamie Thomson baru-baru ini menunjukkan bahwa ada bug "hasil yang salah" di SQL Server yang dapat muncul dengan sendirinya jika kondisi berikut ini benar:
- Anda memiliki tampilan terindeks yang menggabungkan setidaknya dua tabel;
- tabel tersebut dibatasi di kedua arah oleh kunci asing satu kolom;
- Anda melakukan pembaruan pada tabel dasar menggunakan
MERGE
yang mencakupUPDATE
dan (DELETE
atauINSERT
) tindakan; dan, - Anda kemudian mengeluarkan kueri yang mereferensikan indeks pada tampilan (sengaja atau tidak).
Sayangnya, artikel Basis Pengetahuan yang menjelaskan masalah (KB #2756471) cukup detail. Mereka tidak memberitahu Anda bagaimana mereproduksi masalah, atau bahkan apa, khususnya, Anda harus mencari untuk melihat apakah ini mempengaruhi Anda; dan mereka bahkan tidak menyebutkan MERGE
(yang sebenarnya adalah inti masalahnya, bukan NOEXPAND
, dan bukan pembaruan sederhana). Ada beberapa detail tambahan di item Connect yang membawa perbaikan; semoga artikel KB akan diperbarui dengan lebih detail sebelum lama.
Sementara itu, hasil yang mungkin Anda lihat adalah data yang salah – atau lebih baik lagi, data basi :Kueri mungkin menunjukkan versi lama dari baris yang diperbarui! Saya menghabiskan beberapa menit mencoba untuk mereproduksi skenario ini di AdventureWorks, dan gagal total. Untungnya, Paul White (blog | @SQL_Kiwi) menulis postingan luar biasa yang menjelaskan skenario dan menampilkan repro lengkap dari masalah tersebut.
Saya rasa saya tidak bisa menekankan betapa seriusnya ini.
Tentunya jutaan pelanggan menggunakan tampilan yang diindeks, banyak dari mereka telah memigrasikan kode DML mereka untuk menggunakan MERGE
, dan sebagian besar ada di Edisi Perusahaan (atau tidak tetapi menggunakan NOEXPAND
petunjuk atau merujuk indeks secara langsung). Paul dengan cepat menunjukkan bahwa NOEXPAND
tidak diperlukan untuk mereproduksi masalah di Edisi Perusahaan, dan juga menemukan banyak detail lain yang diperlukan untuk mereproduksi bug.
Postingan ini tidak dimaksudkan untuk mencuri guntur dari postingan Jamie atau Paul; hanya upaya untuk menegaskan kembali keprihatinan dan untuk meningkatkan kesadaran akan masalah ini. Jika Anda terbiasa mengabaikan Pembaruan Kumulatif, memilih untuk menunggu Paket Layanan, dan ada kemungkinan masalah ini dapat memengaruhi Anda saat ini, Anda berhutang pada diri Anda sendiri, belum lagi pemangku kepentingan dan pelanggan Anda, untuk mengambil masalah ini dengan serius.
Jadi apa yang harus kamu lakukan?
Nah, apa yang Anda lakukan selanjutnya tergantung pada versi dan edisi SQL Server yang Anda jalankan, dan apakah bug tersebut benar-benar memengaruhi Anda (atau bisa).
- Anda harus memperbarui ke Pembaruan Kumulatif terbaru untuk cabang Anda:
Cabang Tetap di CU Bangun Build minimum diperlukan
untuk menerapkan pembaruanArtikel KB
(Unduh)Paket Layanan 3 2008 CU #8 10.00.5828 10.00.5500 KB #2771833 Paket Layanan 1 R2 2008 CU #10 10.50.2868 10.50.2500 KB #2783135 Paket Layanan 2 R2 2008 CU #4 10.50.4270 10.00.4000 KB #2777358 RTM 2012 CU #5 11.00.2395 11.00.2100 KB #2777772 Paket Layanan 1 2012 CU #2 11.00.3339 11.00.3000 KB #2790947 Tabel 1 :Build yang berisi perbaikan
- Jika Anda tidak menerapkan perbaikan, maka Anda perlu menguji semua referensi ke tampilan Anda untuk memvalidasi bahwa mereka mengembalikan hasil yang benar dalam semua kasus – termasuk setelah Anda memperbarui tabel dasar menggunakan
MERGE
. Jika tidak (atau Anda menduga bahwa mereka mungkin akan terpengaruh nanti), maka Anda harus membangun kembali indeks berkerumun pada semua tampilan yang terpengaruh (atau memperbaiki tampilan yang diindeks menggunakanDBCC CHECKTABLE
, seperti yang dijelaskan Paul dalam postingannya), dan berhenti menggunakanMERGE
terhadap tabel ini sampai Anda menerapkan perbaikan. Jika Anda terus menggunakanMERGE
terhadap tabel dasar, bersiaplah untuk terus memperbaiki tampilan untuk menghindari masalah.
- Perbaikan yang lebih cepat adalah mencegah tampilan terindeks yang rusak agar tidak digunakan sama sekali, dengan menggunakan salah satu metode berikut yang diperlukan:
- terapkan petunjuk kueri
OPTION (EXPAND VIEWS)
untuk semua pertanyaan yang relevan; - hapus semua referensi eksplisit ke indeks pada tampilan;
- di Standar atau edisi lain di mana tampilan yang diindeks tidak dicocokkan secara otomatis, hapus semua contoh
NOEXPAND
.
Tapi ini, tentu saja, sebagian besar akan mengalahkan tujuan tampilan yang diindeks – mungkin juga menjatuhkan indeks. Yang mengatakan, biasanya lebih baik untuk mendapatkan hasil yang benar secara perlahan, daripada mendapatkan hasil yang salah dengan cepat; jadi mungkin tidak apa-apa.
- terapkan petunjuk kueri
SQL Server 2008 SP3
SQL Server 2008 R2 SP1/SP2
SQL Server 2012 RTM/SP1
Opsi Anda jika Anda menggunakan salah satu dari build ini:
SQL Server 2008 RTM/SP1/SP2
SQL Server 2008 R2 RTM
Sayangnya, Anda menggunakan build yang tidak lagi mendukung mainstream, dan kecil kemungkinan masalah ini akan diperbaiki untuk Anda (kecuali jika Anda menggunakan dukungan yang diperluas dan Anda membuat banyak gangguan). Jadi opsi Anda terbatas di sini – pindah ke cabang yang didukung sesuai tabel di atas, dan terapkan Pembaruan Kumulatif, atau pilih salah satu opsi lain yang disebutkan sebelumnya.
SQL Server 2000
SQL Server 2005
Kabar buruknya adalah Anda juga menggunakan build yang tidak lagi didukung. Kabar baiknya adalah bahwa dalam kasus khusus ini tidak masalah – Anda tidak dapat menggunakan MERGE
lagi pula, jadi bug ini tidak dapat memengaruhi Anda.
Masalah MERGE lainnya
Sayangnya, ini jauh dari bug pertama yang kami lihat dengan MERGE
, dan kemungkinan itu bukan yang terakhir. Berikut adalah pilihan cepat dari selusin MERGE
bug yang masih ditandai sebagai aktif di Connect:
- #773895 :MERGE Salah Melaporkan Pelanggaran Kunci Unik
- #766165 :MERGE mengevaluasi indeks yang difilter per baris, bukan setelah operasi, yang menyebabkan pelanggaran indeks yang difilter
- #723696 :Penggabungan dasar yang menyebabkan kebuntuan
- #713699 :Pemeriksaan pernyataan sistem gagal ("cxrowset.cpp":1528)
- #699055 :Gabungkan paket kueri memungkinkan FK dan PERIKSA pelanggaran batasan
- #685800 :Parameterisasi DELETE dan MERGE Izinkan Pelanggaran Batasan Kunci Asing
- #654746 :penggabungan di SQL2008 SP2 masih mengalami "Mencoba menetapkan nilai kolom yang tidak dapat NULL ke NULL"
- #635778 :NOT MATCHED dan MATCHED bagian dari pernyataan SQL MERGE tidak dioptimalkan
- #633132 :PENGGABUNGAN DENGAN SUMBER YANG DIFILTER tidak berfungsi dengan baik
- #596086 :MERGE statement bug saat INSERT/DELETE menggunakan dan memfilter indeks
- #583719 :Pernyataan MERGE memperlakukan kolom terhitung yang tidak dapat dibatalkan secara salah dalam beberapa skenario
- #539084 :MERGE Stmt :Kondisi pencarian pada kolom non-kunci dan ORDER BY dalam tabel turunan sumber memecah MERGE sepenuhnya
Sekarang, mungkin beberapa bug ini sebenarnya telah diperbaiki, tetapi statusnya salah karena loop kembali ke Connect belum ditutup. Bahkan jika itu masalahnya, itu tidak benar untuk mereka semua (dan berpotensi untuk orang lain yang tidak saya temukan).
Selain itu, telah ditunjukkan oleh Dan Guzman bahwa MERGE
tidak kebal dari kondisi balapan dan masalah konkurensi lainnya. Solusinya adalah dengan menggunakan HOLDLOCK
(atau tingkat isolasi yang lebih tinggi); namun, adalah kesalahpahaman umum bahwa MERGE
sepenuhnya atom dan tidak rentan terhadap masalah ini sama sekali. Oleh karena itu saya akan bertanya-tanya:berapa banyak MERGE
pernyataan di luar sana termasuk HOLDLOCK
(atau sedang dieksekusi di bawah SERIALIZABLE
)? Berapa banyak yang telah diuji secara menyeluruh untuk masalah yang berkaitan dengan konkurensi?
Kesimpulan
Secara pribadi, saya pikir sintaksnya bagus (walaupun menakutkan untuk dipelajari), tetapi setiap kali masalah muncul, itu mengikis kepercayaan saya pada kepraktisan mengganti DML yang ada dengan konstruksi baru.
Dengan mengingat hal itu, bukan menjadi Chicken Little, tetapi saya tidak akan merasa nyaman merekomendasikan siapa pun untuk menggunakan MERGE
kecuali mereka menerapkan pengujian yang sangat komprehensif. Beberapa masalah ini juga hadir dengan UPSERT
standar metodologi, tetapi masalahnya lebih jelas di sana. MERGE
, hanya melalui sifat satu-pernyataannya, membuat Anda ingin percaya pada sihir. Mungkin suatu hari nanti itu akan berhasil, tetapi sekarang saya tahu itu tidak akan dapat melihat seseorang menjadi dua tanpa bantuan yang serius.