Pemicu SQL Server adalah tipe khusus dari prosedur tersimpan yang dijalankan secara otomatis ketika suatu peristiwa terjadi di server database tertentu. SQL Server memberi kami dua jenis pemicu utama:DML Pemicu dan DDL pemicu. Pemicu DDL akan dipicu sebagai respons terhadap peristiwa Data Definition Language (DDL) yang berbeda, seperti mengeksekusi pernyataan T-SQL CREATE, ALTER, DROP, GRANT, DENY, dan REVOKE. Pemicu DDL dapat merespons tindakan DDL dengan mencegah perubahan ini memengaruhi database, melakukan tindakan lain sebagai respons terhadap tindakan DDL ini, atau merekam perubahan yang dijalankan terhadap database.
Pemicu DML SQL Server adalah tipe khusus prosedur tersimpan yang dirancang untuk melakukan urutan tindakan pada tabel database, tempat pemicu dilampirkan, saat peristiwa Bahasa Manipulasi Data (DML), seperti INSERT, UPDATE, atau DELETE tindakan, terjadi untuk mengubah konten tabel atau tampilan database, terlepas dari apakah baris tabel terpengaruh atau tidak. Pemicu berbeda dari prosedur tersimpan di mana pemicu dipicu secara otomatis ketika terjadi modifikasi data yang telah ditentukan sebelumnya. Pemicu DML dapat digunakan untuk menjaga integritas data dan menegakkan aturan bisnis perusahaan, sama seperti fungsi pemeriksaan tabel dan batasan kunci asing, dengan melakukan proses audit dan tindakan pasca DML lainnya. Anda dapat menggunakan pemicu DML untuk membuat kueri tabel lain dan melakukan kueri T-SQL yang kompleks.
Jika pemicu diaktifkan, jenis tabel virtual khusus yang disebut Dimasukkan dan Dihapus tabel akan digunakan untuk menyimpan nilai data sebelum dan sesudah modifikasi. Pernyataan pemicu akan bekerja di bawah cakupan transaksi yang sama yang memicu pemicu itu. Ini berarti bahwa transaksi tidak akan dilakukan sepenuhnya sampai pernyataan pemicu berhasil diselesaikan. Di sisi lain, transaksi akan dibatalkan jika pernyataan pemicu gagal.
Ada dua jenis pemicu DML:AFTER atau UNTUK pemicu dan BUKAN pemicu. Pemicu AFTER akan diaktifkan dan dieksekusi setelah melakukan tindakan INSERT, UPDATE, atau DELETE yang berhasil mengaktifkannya. Selain itu, tindakan kaskade referensial dan pemeriksaan batasan harus berhasil sebelum memicu pemicu. Pemicu AFTER hanya dapat ditentukan pada tingkat tabel tanpa kemungkinan mendefinisikannya pada tampilan. BUKAN pemicu digunakan untuk mengganti pernyataan tindakan yang memicu pemicu dengan pernyataan yang disediakan di pemicu, mengembalikan pernyataan itu setelah memunculkan kesalahan saat seseorang mencoba melakukan tindakan yang melanggar kebijakan tertentu, seperti memperbarui kolom keuangan penting atau menulis perubahan ke dalam tabel audit sebelum melakukan perubahan. Pemicu BUKAN memungkinkan Anda untuk MEMASUKKAN, MEMPERBARUI, atau MENGHAPUS data dari tampilan yang mereferensikan data dari beberapa tabel, selain kemungkinan untuk menolak bagian dari kueri kumpulan dan menjalankan bagian lain dari kumpulan itu dengan sukses. Pemicu INSTEAD OF tidak dapat digunakan dengan tampilan yang dapat diperbarui yang memiliki WITH CHECK OPTION dan dalam tabel dengan hubungan referensial yang menentukan tindakan kaskade pada DELETE atau UPDATE.
Setelah membahas pemicu secara teoritis, kami akan mulai menunjukkan apa yang kami diskusikan secara praktis. Dalam demo yang akan datang, kami akan menunjukkan situasi berbeda di mana kami dapat mengambil manfaat dari pemicu SQL Server.
SETELAH… Pemicu DML
Asumsikan bahwa kita perlu melacak tindakan DML yang dilakukan pada tabel tertentu dan menulis log ini dalam tabel riwayat, di mana ID rekaman yang dimasukkan, diperbarui, atau dihapus dan tindakan yang dilakukan akan ditulis ke tabel riwayat. Pernyataan T-SQL CREATE TABLE di bawah ini dapat digunakan untuk membuat tabel sumber dan riwayat:
CREATE TABLE TriggerDemo_Parent ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT ) GO CREATE TABLE TriggerDemo_History ( ID INT IDENTITY (1,1) PRIMARY KEY, ParentID INT, PerformedAction VARCHAR (50), ) GO
Untuk melacak operasi INSERT, kami akan membuat pemicu DML yang akan diaktifkan setelah melakukan operasi INSERT pada tabel induk. Pemicu ini akan mengambil nilai ID yang terakhir dimasukkan ke tabel induk tersebut dari tabel yang dimasukkan virtual, seperti dalam pernyataan T-SQL CREATE TRIGGER di bawah ini:
CREATE TRIGGER AfterInsertTrigger ON TriggerDemo_Parent AFTER INSERT AS INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1 inserted.ID FROM inserted), 'Insert') GO
Pelacakan operasi DELETE dapat dicapai dengan membuat pemicu DML yang dipicu setelah melakukan operasi DELETE pada tabel induk. Sekali lagi, trigger akan mengambil nilai ID dari record yang terakhir dihapus dari tabel parent dari tabel virtual yang dihapus, seperti pada pernyataan CREATE TRIGGER T-SQL di bawah ini:
CREATE TRIGGER AfterDeleteTrigger ON TriggerDemo_Parent AFTER DELETE AS INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1 deleted.ID FROM deleted), 'Delete') GO
Terakhir, kami juga akan melacak operasi UPDATE dengan membuat pemicu DML yang akan diaktifkan setelah melakukan operasi UPDATE pada tabel induk. Dalam pemicu ini, kami akan mengambil nilai ID terakhir yang diperbarui dari tabel induk tersebut dari tabel yang dimasukkan virtual, dengan mempertimbangkan bahwa proses UPDATE dilakukan dengan menghapus catatan dan memasukkan catatan baru dengan nilai yang diperbarui, seperti pada CREATE TRIGGER Pernyataan T-SQL di bawah ini:
CREATE TRIGGER AfterUPDATETrigger ON TriggerDemo_Parent AFTER UPDATE AS INSERT INTO TriggerDemo_History VALUES ((SELECT TOP 1 inserted.ID FROM inserted), 'UPDATE') GO
Tabel dan pemicu sudah siap sekarang untuk pengujian kami. Jika Anda mencoba memasukkan record baru ke tabel induk menggunakan pernyataan T-SQL INSERT INTO di bawah ini:
INSERT INTO TriggerDemo_Parent VALUES ('AAA','BBB',500)
Kemudian dengan memeriksa rencana eksekusi yang dihasilkan dengan mengeksekusi pernyataan INSERT sebelumnya, Anda akan melihat bahwa dua operasi penyisipan akan dilakukan, mempengaruhi dua tabel; tabel induk dengan nilai yang ditentukan dalam pernyataan INSERT dan tabel riwayat karena memicu pemicu AFTER INSERT, seperti yang ditunjukkan dalam rencana eksekusi di bawah ini:
Juga jelas ketika Anda memeriksa data yang dimasukkan ke dalam tabel induk dan riwayat menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_Parent GO SELECT * FROM TriggerDemo_History
Dimana nilai-nilai yang ditentukan dalam pernyataan INSERT akan dimasukkan ke dalam tabel induk, dan log insert yang berisi ID record yang dimasukkan dan operasi yang dilakukan akan dimasukkan ke dalam tabel riwayat, seperti yang ditunjukkan pada hasil di bawah ini:
Sekarang, jika Anda mencoba memperbarui catatan yang ada di tabel induk menggunakan pernyataan T-SQL UPDATE di bawah ini:
UPDATE TriggerDemo_Parent SET Emp_Salary=550 WHERE ID=1
Dan periksa rencana eksekusi yang dihasilkan dengan mengeksekusi pernyataan UPDATE sebelumnya, Anda akan melihat bahwa operasi pembaruan akan diikuti oleh operasi penyisipan yang memengaruhi dua tabel berbeda; tabel induk akan diperbarui dengan nilai yang ditentukan dalam pernyataan UPDATE dan operasi penyisipan ke dalam tabel riwayat karena memicu pemicu AFTER UPDATE, seperti yang ditunjukkan dalam rencana eksekusi di bawah ini:
Memeriksa catatan tabel induk dan riwayat menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_Parent GO SELECT * FROM TriggerDemo_History
Anda akan melihat bahwa pernyataan pembaruan akan mengubah nilai Emp_Salary di tabel induk dengan nilai yang ditentukan dalam pernyataan UPDATE, dan log pembaruan yang berisi ID catatan yang diperbarui dan operasi yang dilakukan akan dimasukkan ke dalam tabel riwayat, sebagai ditunjukkan pada hasil di bawah ini:
Dalam skenario terakhir pemicu AFTER DML, kami akan melacak penghapusan record yang ada dari tabel induk menggunakan pernyataan DELETE T-SQL di bawah ini:
DELETE FROM TriggerDemo_Parent WHERE ID=1
Kemudian periksa rencana eksekusi yang dihasilkan dengan mengeksekusi pernyataan DELETE sebelumnya, Anda akan melihat bahwa operasi DELETE akan diikuti oleh operasi penyisipan, yang mempengaruhi dua tabel yang berbeda; tabel induk dari mana catatan dengan ID yang diberikan dalam klausa WHERE dari pernyataan DELETE akan dihapus dan operasi penyisipan ke dalam tabel riwayat karena memicu pemicu AFTER DELETE, seperti yang ditunjukkan dalam rencana eksekusi di bawah ini:
Jika Anda memeriksa catatan tabel induk dan riwayat menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_Parent GO SELECT * FROM TriggerDemo_History
Anda akan melihat bahwa catatan dengan nilai ID sama dengan 1 telah dihapus dari tabel induk yang disediakan dalam pernyataan DELETE, dan log hapus yang berisi ID catatan yang dihapus dan operasi yang dilakukan akan dimasukkan ke dalam tabel riwayat , seperti yang ditunjukkan pada hasil di bawah ini:
BUKAN… Pemicu DML
Jenis pemicu DML kedua adalah pemicu BUKAN DML. Seperti disebutkan sebelumnya, BUKAN pemicu akan menimpa pernyataan tindakan yang memicu pemicu dengan pernyataan yang disediakan di pemicu. Asumsikan bahwa kita perlu mencatat tindakan DML yang coba dilakukan pengguna pada tabel tertentu, tanpa mengizinkan mereka melakukan tindakan tersebut. Pernyataan T-SQL CREATE TABLE di bawah ini dapat digunakan untuk membuat tabel sumber dan alternatif:
CREATE TABLE TriggerDemo_NewParent ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT ) GO CREATE TABLE TriggerDemo_InsteadParent ( ID INT IDENTITY (1,1) PRIMARY KEY, ParentID INT, PerformedAction VARCHAR (50), ) GO
Setelah membuat dua tabel, kami akan memasukkan satu record ke dalam tabel sumber untuk demo kami menggunakan pernyataan INSERT INTO di bawah ini:
INSERT INTO TriggerDemo_NewParent VALUES ('AA','BB', 500)
Untuk demo ini, kami akan membuat tiga pemicu untuk menimpa operasi INSERT, UPDATE, dan DELETE. Pemicu pertama akan digunakan untuk mencegah operasi penyisipan pada tabel induk dan log yang berubah menjadi tabel alternatif. Pemicu dibuat menggunakan pernyataan CREATE TRIGGER T-SQL di bawah ini:
CREATE TRIGGER InsteadOfInsertTrigger ON TriggerDemo_NewParent INSTEAD OF INSERT AS INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1 inserted.ID FROM inserted), 'Trying to Insert new ID') GO
Pemicu kedua digunakan untuk mencegah operasi pembaruan pada tabel induk dan log yang berubah menjadi tabel alternatif. Pemicu ini dibuat seperti di bawah ini:
CREATE TRIGGER InsteadOfUpdateTrigger ON TriggerDemo_NewParent INSTEAD OF UPDATE AS INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1 inserted.ID FROM inserted), 'Trying to Update an existing ID') GO
Pemicu terakhir akan digunakan untuk mencegah operasi penghapusan pada tabel induk dan log yang berubah menjadi tabel alternatif. Pemicu ini dibuat sebagai berikut:
CREATE TRIGGER InsteadOfDeleteTrigger ON TriggerDemo_NewParent INSTEAD OF DELETE AS INSERT INTO TriggerDemo_InsteadParent VALUES ((SELECT TOP 1 inserted.ID FROM inserted), 'Trying to Delete an existing ID') GO
Dua tabel dan tiga pemicu sudah siap sekarang. Jika Anda mencoba memasukkan nilai baru ke dalam tabel induk menggunakan pernyataan T-SQL INSERT INTO di bawah ini:
INSERT INTO TriggerDemo_NewParent VALUES ('CCC','DDD',500)
Kemudian periksa catatan tabel induk dan alternatif menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_NewParent GO SELECT * FROM TriggerDemo_InsteadParent
Karena fakta bahwa kami memiliki pemicu INSTEAD OF INSERT di tabel induk, Anda akan melihat dari hasil bahwa tidak ada catatan baru yang dimasukkan ke dalam tabel induk, dan log untuk operasi penyisipan dimasukkan ke dalam tabel alternatif, seperti yang ditunjukkan pada hasil di bawah ini:
Mencoba memperbarui catatan yang ada di tabel induk menggunakan pernyataan T-SQL UPDATE di bawah ini:
UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1
Kemudian periksa catatan tabel induk dan alternatif menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_NewParent GO SELECT * FROM TriggerDemo_InsteadParent
Anda akan melihat dari hasil bahwa nilai Emp_Salary dari record dengan nilai ID sama dengan 1 dari tabel induk tidak akan diubah, dan log untuk operasi pembaruan dimasukkan ke dalam tabel alternatif karena memiliki trigger INSTEAD OF UPDATE di tabel induk, seperti yang ditunjukkan pada hasil di bawah ini:
Terakhir, jika kita mencoba menghapus record yang ada dari tabel induk menggunakan pernyataan T-SQL DELETE di bawah ini:
DELETE FROM TriggerDemo_NewParent WHERE ID=1
Dan periksa catatan tabel induk dan alternatif menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_NewParent GO SELECT * FROM TriggerDemo_InsteadParent
Akan jelas dari hasil bahwa catatan dengan nilai ID sama dengan 1 dari tabel induk tidak akan dihapus, dan log untuk operasi penghapusan dimasukkan ke dalam tabel alternatif karena memiliki pemicu INSTEAD OF DELETE di induk tabel, seperti yang ditunjukkan pada hasil di bawah ini:
SETELAH… Pemicu DML dengan Pesan
Pemicu AFTER dapat digunakan juga untuk memunculkan pesan peringatan bagi pengguna. Dalam hal ini, kueri akan menjadi pesan informasi yang tidak akan mencegah eksekusi pernyataan yang memicu pemicu itu. Mari kita hapus pemicu INSTEAD OF UPDATE yang dibuat sebelumnya dan ganti dengan pemicu SETELAH UPDATE lain yang akan memunculkan kesalahan peringatan setelah melakukan operasi pembaruan menggunakan pernyataan T-SQL DROP/CREATE TRIGGER di bawah ini:
DROP TRIGGER InsteadOfUpdateTrigger CREATE TRIGGER ReminderTrigger ON TriggerDemo_NewParent AFTER UPDATE AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10); GO
Jika Anda mencoba memperbarui nilai Emp_Salary karyawan dengan nilai ID sama dengan 1 menggunakan pernyataan UDPATE di bawah ini:
UPDATE TriggerDemo_NewParent SET Emp_Salary=550 WHERE ID=1
Pesan kesalahan akan dimunculkan di Pesan tab, yang berisi pesan yang disediakan di pemicu yang dibuat, seperti yang ditunjukkan di bawah ini:
Memeriksa data tabel induk menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_NewParent
Anda akan melihat dari hasil bahwa Emp_Salary berhasil diperbarui, seperti yang ditunjukkan di bawah ini:
Jika Anda memerlukan pemicu AFTER UPDATE untuk menghentikan operasi pembaruan setelah memunculkan pesan kesalahan, ROLLBACK pernyataan dapat ditambahkan ke pemicu untuk mengembalikan operasi pembaruan yang memicu pemicu itu, mengingat bahwa pemicu dan pernyataan yang mengaktifkan pemicu akan dieksekusi dalam transaksi yang sama. Ini dapat dicapai dengan menggunakan pernyataan T-SQL ALTER TRIGGER, lihat:
ALTER TRIGGER ReminderTrigger ON TriggerDemo_NewParent AFTER UPDATE AS RAISERROR ('An Update is performed on the TriggerDemo_NewParent table', 16, 10); ROLLBACK GO
Jika Anda mencoba memperbarui nilai Emp_Salary karyawan dengan ID sama dengan 1 menggunakan pernyataan UPDATE di bawah ini:
UPDATE TriggerDemo_NewParent SET Emp_Salary=700 WHERE ID=1
Sekali lagi, pesan kesalahan akan ditampilkan di Pesan tab, tetapi kali ini, operasi pembaruan akan dibatalkan sepenuhnya, seperti yang ditunjukkan pada pesan kesalahan di bawah ini:
Memeriksa nilai dari tabel sumber menggunakan pernyataan SELECT di bawah ini:
SELECT * FROM TriggerDemo_NewParent
Anda akan melihat bahwa nilai Emp_Salary tidak berubah, karena pemicu AFTER UPDATE membatalkan keseluruhan transaksi setelah memunculkan pesan kesalahan, seperti yang ditunjukkan pada hasil tabel di bawah ini:
Kerugian Pemicu
Dengan semua keuntungan yang disebutkan dari pemicu SQL Server, pemicu meningkatkan kompleksitas database. Jika pemicu dirancang dengan buruk atau digunakan secara berlebihan, itu akan menyebabkan masalah kinerja utama, seperti sesi yang diblokir, karena memperpanjang umur transaksi untuk waktu yang lebih lama, overhead tambahan pada sistem karena menjalankannya setiap kali INSERT, UPDATE atau Tindakan DELETE dilakukan atau dapat menyebabkan masalah kehilangan data. Selain itu, tidak mudah untuk melihat dan melacak pemicu basis data, terutama jika tidak ada dokumentasi tentangnya karena tidak terlihat oleh pengembang dan aplikasi.
Alternatif Pemicu … Terapkan Integritas
Jika ditemukan bahwa pemicu merusak kinerja instans SQL Server Anda, Anda harus menggantinya dengan solusi lain. Misalnya, daripada menggunakan pemicu untuk menegakkan integritas entitas, itu harus diterapkan pada tingkat terendah dengan menggunakan KUNCI UTAMA dan batasan UNIK. Hal yang sama diterapkan pada integritas domain yang harus ditegakkan melalui batasan CHECK, dan integritas referensial yang harus ditegakkan melalui batasan FOREIGN KEY. Anda dapat menggunakan pemicu DML hanya jika fitur yang didukung oleh batasan tertentu tidak dapat memenuhi persyaratan aplikasi Anda.
Mari kita bandingkan antara menegakkan integritas domain menggunakan pemicu DML dan menggunakan batasan CHECK. Asumsikan bahwa kita perlu memaksakan memasukkan nilai positif hanya ke kolom Emp_Salary. Kita akan mulai dengan membuat tabel sederhana menggunakan pernyataan T-SQL CREATE TABLE di bawah ini:
CREATE TABLE EmployeeSalaryTrigger ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT ) GO
Kemudian tentukan pemicu AFTER INSERT DML yang memastikan bahwa Anda memasukkan nilai positif ke kolom Emp_Salary dengan mengembalikan transaksi jika pengguna memasukkan nilai gaji negatif, menggunakan pernyataan CREATE TRIGGER T-SQL di bawah ini:
CREATE TRIGGER TRGR_EmployeeSalary ON EmployeeSalaryTrigger AFTER INSERT AS DECLARE @EmpSal AS INT SET @EmpSal = (SELECT TOP 1 inserted.Emp_Salary FROM inserted) IF @EmpSal<0 BEGIN RAISERROR ('Cannot insert negative salary',16,10); ROLLBACK END
Untuk tujuan perbandingan, kita akan membuat tabel sederhana lainnya, dengan skema yang sama, dan mendefinisikan batasan CHECK dalam pernyataan CREATE TABLE untuk menerima hanya nilai positif di kolom Emp_Salary, seperti yang ditunjukkan di bawah ini:
CREATE TABLE EmployeeSalaryConstraint ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT CONSTRAINT EmpSal CHECK (Emp_Salary >=0) ) GO
Jika Anda mencoba memasukkan catatan di bawah yang berisi nilai Emp_Salary negatif ke dalam tabel pertama yang memiliki pemicu yang telah ditentukan, gunakan pernyataan INSERT INTO di bawah ini:
INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4) GO
Pernyataan INSERT akan gagal memunculkan pesan kesalahan yang menunjukkan bahwa Anda tidak dapat memasukkan nilai negatif ke kolom Emp_Salary dan mengembalikan keseluruhan transaksi karena memiliki pemicu AFTER INSERT, seperti yang ditunjukkan pada pesan kesalahan di bawah ini:
Juga, jika Anda mencoba memasukkan catatan yang sama yang berisi nilai Emp_Salary negatif ke dalam tabel kedua yang memiliki batasan CHECK yang telah ditentukan sebelumnya menggunakan pernyataan INSERT INTO di bawah ini:
INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4)
Pernyataan INSERT akan gagal lagi yang menunjukkan bahwa Anda mencoba memasukkan nilai yang bertentangan dengan kondisi kendala CHECK, seperti yang ditunjukkan pada pesan kesalahan di bawah ini:
Dari hasil sebelumnya, Anda melihat bahwa baik pemicu maupun metode kendala CHECK mencapai tujuan dengan mencegah Anda memasukkan nilai Emp_Salary negatif. Tapi mana yang lebih baik? Mari kita bandingkan kinerja kedua metode dengan memeriksa bobot rencana eksekusi untuk masing-masing metode. Dari rencana eksekusi yang dihasilkan setelah menjalankan dua kueri, Anda akan melihat bahwa bobot metode pemicu adalah tiga kali bobot metode CHECK constraint, seperti yang ditunjukkan pada perbandingan rencana eksekusi di bawah ini:
Juga, untuk membandingkan waktu eksekusi yang digunakan oleh masing-masing, mari kita jalankan masing-masing 1000 kali menggunakan pernyataan T-SQL di bawah ini:
INSERT INTO EmployeeSalaryTrigger VALUES('Ali', 'Fadi',-4) GO 10000 INSERT INTO EmployeeSalaryConstraint VALUES ('Ali', 'Fadi',-4) GO 10000
Anda akan melihat bahwa metode pertama yang menggunakan pemicu akan memakan waktu sekitar 31 md untuk dieksekusi sepenuhnya, di mana metode kedua yang menggunakan batasan CHECK hanya membutuhkan waktu 17 md , yaitu sekitar 0,5 kali diperlukan dalam metode menggunakan pemicu. Hal ini disebabkan oleh fakta bahwa pemicu akan memperpanjang umur transaksi dan akan mengembalikan kueri yang memicu pemicu setelah menjalankannya ketika pelanggaran integritas ditemukan, menyebabkan penurunan kinerja karena proses rollback. Kasusnya berbeda saat menggunakan constraint CHECK, di mana constraint akan melakukan tugasnya sebelum melakukan modifikasi apa pun pada data, tidak memerlukan rollback jika terjadi pelanggaran.
Alternatif Pemicu … Audit
Seperti yang kami sebutkan sebelumnya, pemicu juga dapat digunakan untuk mengaudit dan melacak perubahan yang dilakukan pada tabel tertentu. Jika metode audit ini menyebabkan penurunan kinerja di instans SQL Server Anda, Anda dapat dengan mudah menggantinya dengan OUTPUT ayat. Klausa OUTPUT mengembalikan informasi tentang setiap baris yang dipengaruhi oleh operasi INSERT, UPDATE atau DELETE, dalam bentuk pesan konfirmasi atau nilai yang dapat dimasukkan ke dalam tabel historis. Metode klausa OUTPUT juga memberi kita kontrol lebih pada kode yang dieksekusi, karena akan ditambahkan ke pernyataan penyisipan, modifikasi, atau penghapusan data itu sendiri kapan pun Anda mau, berlawanan dengan pemicu yang akan selalu dieksekusi.
Mari kita bandingkan antara memasukkan penyisipan data dan modifikasi ke dalam tabel riwayat menggunakan pemicu DML dan menggunakan klausa OUTPUT. Kita akan mulai dengan membuat tabel produksi dan sejarah di bawah menggunakan pernyataan T-SQL CREATE TABLE di bawah ini:
CREATE TABLE TriggerDemo_Prod ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT ) GO CREATE TABLE TriggerDemo_ProdHistory ( ID INT IDENTITY (1,1) PRIMARY KEY, ProdID INT, ProdSalary INT, TS DATETIME, ) GO
Setelah kedua tabel berhasil dibuat, kami akan membuat pemicu DML AFTER INSERT, UPDATE yang akan menulis catatan ke dalam tabel riwayat jika ada baris baru yang dimasukkan ke dalam tabel produksi atau catatan yang ada dimodifikasi menggunakan pernyataan T-SQL CREATE TRIGGER di bawah ini:
CREATE TRIGGER ProdHistory ON TriggerDemo_Prod AFTER INSERT, UPDATE AS INSERT INTO TriggerDemo_ProdHistory VALUES ( (SELECT TOP 1 inserted.ID FROM inserted),(SELECT TOP 1 inserted.Emp_Salary FROM inserted), GETDATE()) GO
Untuk membandingkan pencatatan perubahan menggunakan metode pemicu dan klausa OUTPUT, kita perlu membuat dua tabel sederhana baru, tabel produksi dan tabel histori, dengan skema yang sama seperti dua tabel sebelumnya, tetapi kali ini tanpa mendefinisikan pemicu, menggunakan CREATE TABLE pernyataan T-SQL di bawah ini:
CREATE TABLE OutputDemo_Prod ( ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT ) GO CREATE TABLE OutputDemo_ProdHistory ( ID INT IDENTITY (1,1) PRIMARY KEY, ProdID INT, ProdSalary INT, TS DATETIME, ) GO
Sekarang keempat tabel siap untuk pengujian. Kami akan memasukkan satu record ke dalam tabel produksi pertama yang memiliki trigger menggunakan pernyataan T-SQL INSERT INTO di bawah ini:
INSERT INTO TriggerDemo_Prod values('AA','BB', 750) GO
Kemudian kita akan memasukkan record yang sama ke dalam tabel produksi kedua menggunakan klausa OUTPUT. Pernyataan INSERT INTO di bawah ini akan bertindak sebagai dua pernyataan sisipan; yang pertama akan menyisipkan catatan yang sama ke dalam tabel produksi dan pernyataan penyisipan kedua di samping klausa OUTPUT akan menyisipkan log penyisipan ke dalam tabel riwayat:
INSERT INTO OutputDemo_Prod OUTPUT inserted.ID, inserted.Emp_Salary, GETDATE() INTO OutputDemo_ProdHistory values('AA','BB', 750) GO
Memeriksa data yang dimasukkan ke dalam empat tabel produksi dan riwayat, Anda akan melihat bahwa kedua metode, metode pemicu dan OUTPUT, akan berhasil menulis log yang sama ke dalam tabel riwayat dan dengan cara yang sama, seperti yang ditunjukkan pada hasil di bawah ini:
Dari rencana eksekusi yang dihasilkan setelah menjalankan dua kueri, Anda akan melihat bahwa bobot metode pemicu adalah sekitar (21%+36%) 57% dari bobot keseluruhan, di mana bobot metode OUTPUT sekitar 43% , dengan perbedaan bobot yang kecil, seperti terlihat pada perbandingan rencana eksekusi di bawah ini:
Perbedaan kinerja terlihat jelas saat membandingkan waktu eksekusi yang digunakan oleh setiap metode, di mana pencatatan perubahan menggunakan metode pemicu akan menghabiskan (114+125) 239 md untuk dieksekusi sepenuhnya, dan metode yang menggunakan metode klausa OUTPUT hanya menggunakan 5 md , yaitu 2% waktu yang digunakan dalam metode pemicu, seperti yang ditunjukkan dengan jelas dari Statistik Waktu di bawah ini:
Sekarang jelas dari hasil sebelumnya bahwa menggunakan metode OUTPUT lebih baik daripada menggunakan pemicu untuk audit perubahan.
Tautan Berguna:
- BUAT PEMICU (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
- Pemicu DML https://docs.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers
- Pemicu DDL https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers
- Klausa OUTPUT (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql