Saya punya pemicu UPDATE di atas meja yang mengawasi kolom tertentu yang berubah dari satu nilai tertentu ke nilai lainnya. Ketika ini terjadi, itu memperbarui beberapa data terkait di tabel lain melalui pernyataan UPDATE tunggal.
Hal pertama yang dilakukan pemicu adalah memeriksa untuk melihat apakah ada baris yang diperbarui memiliki nilai kolom ini berubah dari nilai yang dimaksud. Ia hanya bergabung dengan INSERTED ke DELETED dan membandingkan nilai di kolom itu. Jika tidak ada yang memenuhi syarat, itu ditebus lebih awal sehingga pernyataan UPDATE tidak berjalan.
IF NOT EXISTS (
SELECT TOP 1 i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
)
RETURN
Dalam hal ini, CUSTNMBR adalah kunci utama dari tabel yang mendasarinya. Jika saya melakukan pembaruan besar pada tabel ini (katakanlah, 5000+ baris), pernyataan ini membutuhkan AGES, bahkan jika saya belum menyentuh kolom CUSTCLAS. Saya bisa melihatnya berhenti pada pernyataan ini selama beberapa menit di Profiler.
Rencana eksekusi itu aneh. Ini menunjukkan Scan Dimasukkan dengan 3.714 eksekusi, dan ~ 18.5 juta baris output. Itu berjalan melalui filter pada kolom CUSTCLAS. Ini menggabungkan ini (melalui loop bersarang) ke Scan Dihapus (juga difilter pada CUSTCLAS), yang dieksekusi hanya sekali dan memiliki 5.000 baris output.
Apa hal bodoh yang saya lakukan di sini yang menyebabkan ini? Perhatikan bahwa pemicu harus benar-benar menangani pembaruan multi-baris.
EDIT :
Saya juga mencoba menulis seperti ini (kalau-kalau ada yang melakukan sesuatu yang tidak menyenangkan), tapi tetap saja mengerikan.
DECLARE @CUSTNMBR varchar(31)
SELECT TOP 1 @CUSTNMBR = i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
IF @CUSTNMBR IS NULL
RETURN
Jawaban:
Anda bisa mengevaluasi menggunakan eksplisit
INNER MERGE JOIN
atauINNER HASH JOIN
petunjuk tetapi mengingat bahwa Anda mungkin menggunakan tabel ini lagi nanti di pemicu Anda mungkin lebih baik hanya memasukkan konteninserted
dandeleted
tabel ke dalam#temp
tabel yang diindeks dan sedang dilakukan dengan itu.Mereka tidak mendapatkan indeks berguna yang dibuat untuk mereka secara otomatis.
sumber
CUSTNMBR
untuk membuat indeks berkerumun unik) dan menggunakanOPTION (RECOMPILE)
petunjuk untuk mendapatkannya dengan mempertimbangkan jumlah baris atau mungkin hanya menggunakan konvensi penamaan tertentu seperti#i_dbo_YourTable
#trigger_name_i
. Jika saya menggunakan variabel tabel, saya harus semakin mengacaukan kode dengan CREATE TABLEs eksplisit. Kami memiliki pemicu cascading, tetapi bukan pemicu rekursif, jadi saya pikir saya akan aman ...OPTION (RECOMPILE)
agar kardinalitas diperhitungkan.Saya tahu ini telah dijawab tetapi baru saja muncul sebagai baru-baru ini aktif dan saya telah mengalami ini juga untuk tabel dengan jutaan baris. Meskipun tidak mengabaikan jawaban yang diterima, setidaknya saya dapat menambahkan bahwa pengalaman saya menunjukkan bahwa faktor kunci dalam kinerja Pemicu ketika melakukan tes serupa (melihat apakah satu atau lebih kolom benar-benar memiliki nilai berubah) adalah apakah kolom tersebut atau tidak yang diuji sebenarnya adalah bagian dari
UPDATE
pernyataan itu. Saya menemukan bahwa membandingkan kolom antara tabelinserted
dandeleted
yang sebenarnya bukan bagian dariUPDATE
pernyataan memberikan hambatan besar pada kinerja yang sebaliknya tidak ada jika bidang tersebut adalah bagian dariUPDATE
pernyataan (terlepas dari nilai mereka sebenarnya sedang diubah). Mengapa semua pekerjaan itu (yaitu kueri untuk membandingkan bidang N di seluruh baris X) untuk menentukan apakah ada yang berubah jika Anda dapat secara logis mengesampingkan kemungkinan salah satu kolom tersebut diubah, yang jelas tidak mungkin jika tidak ada. dalamSET
klausaUPDATE
pernyataan.Solusi yang saya gunakan adalah menggunakan fungsi UPDATE () yang hanya berfungsi di dalam Pemicu. Fungsi bawaan ini memberi tahu Anda jika kolom ditentukan dalam
UPDATE
pernyataan dan dapat digunakan untuk keluar dari Pemicu jika kolom yang Anda khawatirkan bukan bagian dariUPDATE
. Ini dapat digunakan bersama dengan aSELECT
untuk menentukan apakah kolom-kolom itu, dengan asumsi bahwa mereka ada diUPDATE
, memiliki perubahan yang sebenarnya. Saya memiliki kode di atas beberapa pemicu audit yang terlihat seperti:Logika ini akan berlanjut ke pemicu lainnya jika:
INSERT
SET
klausaUPDATE
dan setidaknya satu dari kolom di satu baris telah berubahThe
NOT (UPDATE...) OR NOT EXISTS()
mungkin terlihat aneh atau mundur, tetapi dirancang untuk menghindari melakukanSELECT
padainserted
dandeleted
tabel jika tidak ada kolom yang relevan adalah bagian dariUPDATE
.Bergantung pada kebutuhan Anda, fungsi COLUMNS_UPDATED () adalah pilihan lain untuk menentukan kolom mana yang merupakan bagian dari
UPDATE
pernyataan.sumber
UPDATE(CUSTCLAS)
dan melewatkan semuanya jika salah (+1). Saya tidak berpikir Anda benar bahwa kolom yang tidak diperbarui tidak tersedia di versi baris seperti yang diperbarui.tempdb
denganDBCC PAGE
tempdb
saya baru saja mencoba skrip ini , menempelkan output ke notepad dan mencari "EEEEEE". Saya melihat output di screenshot di sini . Catat sebelum dan sesudah versi kedua kolom di kedua baris. Mungkin ada banyak cara yang lebih mudah tetapi cukup untuk tujuan saya di sini!tempdb
halaman tidak di sebelahBBBBBB
atauDDDDDD
. Mungkin harus melakukan penyelidikan lagi! Meskipun mungkin ini karenaREPLICATE
panggilan.Saya mungkin mencoba menulis ulang menggunakan jika ada
sumber
http://dave.brittens.org/blog/writing-well-behaved-triggers.html
Menurut Dave, Anda harus menggunakan tabel temp atau variabel tabel dengan indeks, karena tabel virtual INSERTED / DELETED tidak memilikinya. Jika Anda memiliki kemungkinan pemicu rekursif, maka Anda harus menggunakan variabel tabel untuk menghindari tabrakan nama.
Semoga seseorang menemukan ini bermanfaat karena pos aslinya beberapa waktu yang lalu ...
sumber
Kode berikut dapat meningkatkan kinerja pemicu ini. Saya tidak tahu tipe data yang benar dari kolom [custclass] sehingga Anda perlu menyesuaikannya.
Perhatikan bahwa Anda dapat memasukkan kolom tambahan dalam ini dalam salinan memori dari tabel yang dimasukkan dan dihapus jika Anda membutuhkannya dalam kode pemicu Anda. Kunci utama pada tabel ini akan sangat meningkatkan kinerja gabungan saat memperbarui lebih dari beberapa baris sekaligus. Semoga berhasil!
sumber