Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

SQL Server Trigger:Hiểu biết và Các giải pháp thay thế

Trình kích hoạt SQL Server là một loại thủ tục được lưu trữ đặc biệt được thực thi tự động khi một sự kiện xảy ra trong một máy chủ cơ sở dữ liệu cụ thể. SQL Server cung cấp cho chúng tôi hai loại trình kích hoạt chính: DML Trình kích hoạt và DDL gây nên. Các trình kích hoạt DDL sẽ được kích hoạt để đáp ứng với các sự kiện Ngôn ngữ Định nghĩa Dữ liệu (DDL) khác nhau, chẳng hạn như thực thi các câu lệnh CREATE, ALTER, DROP, GRANT, DENY và REVOKE T-SQL. Trình kích hoạt DDL có thể phản hồi các hành động DDL bằng cách ngăn những thay đổi này ảnh hưởng đến cơ sở dữ liệu, thực hiện một hành động khác để đáp lại các hành động DDL này hoặc ghi lại những thay đổi này được thực thi dựa trên cơ sở dữ liệu.

Trình kích hoạt DML của Máy chủ SQL là một loại thủ tục được lưu trữ đặc biệt được thiết kế để thực hiện một chuỗi hành động trên bảng cơ sở dữ liệu, mà trình kích hoạt được đính kèm, khi các sự kiện Ngôn ngữ thao tác dữ liệu (DML), chẳng hạn như CHÈN, CẬP NHẬT hoặc XÓA , xảy ra để sửa đổi nội dung của các bảng hoặc dạng xem cơ sở dữ liệu, bất kể các hàng trong bảng có bị ảnh hưởng hay không. Các trình kích hoạt khác với các thủ tục được lưu trữ ở chỗ các trình kích hoạt được kích hoạt tự động khi xảy ra sửa đổi dữ liệu được xác định trước. Các trình kích hoạt DML có thể được sử dụng để duy trì tính toàn vẹn của dữ liệu và thực thi các quy tắc kinh doanh của công ty, giống như chức năng kiểm tra bảng và ràng buộc khóa ngoại, bằng cách thực hiện các quy trình kiểm tra và các hành động đăng DML khác. Bạn có thể sử dụng trình kích hoạt DML để truy vấn các bảng khác và thực hiện các truy vấn T-SQL phức tạp.

Nếu trình kích hoạt được kích hoạt, một loại bảng ảo đặc biệt được gọi là Đã chèn Đã xóa bảng sẽ được sử dụng để giữ các giá trị dữ liệu trước và sau khi sửa đổi. Câu lệnh kích hoạt sẽ hoạt động trong phạm vi của cùng một giao dịch kích hoạt trình kích hoạt đó. Điều này có nghĩa là giao dịch sẽ không được cam kết hoàn toàn cho đến khi hoàn tất thành công câu lệnh kích hoạt. Mặt khác, giao dịch sẽ được khôi phục nếu câu lệnh kích hoạt không thành công.

Có hai loại trình kích hoạt DML: SAU hoặc CHO kích hoạt và INSTEAD OF cò súng. Trình kích hoạt SAU sẽ được kích hoạt và thực thi sau khi thực hiện hành động CHÈN, CẬP NHẬT hoặc XÓA kích hoạt nó thành công. Ngoài ra, bất kỳ hành động phân tầng tham chiếu nào và kiểm tra ràng buộc sẽ thành công trước khi kích hoạt trình kích hoạt. Trình kích hoạt SAU chỉ có thể được xác định ở cấp bảng mà không có khả năng xác định nó trên các khung nhìn. Trình kích hoạt INSTEAD OF được sử dụng để ghi đè câu lệnh của hành động kích hoạt trình kích hoạt bằng câu lệnh được cung cấp trong trình kích hoạt, khôi phục câu lệnh đó sau khi phát sinh lỗi khi ai đó đang cố gắng thực hiện một hành động vi phạm một chính sách cụ thể, chẳng hạn như cập nhật cột tài chính trọng yếu hoặc ghi thay đổi vào bảng kiểm toán trước khi thực hiện thay đổi. Trình kích hoạt INSTEAD OF cho phép bạn CHÈN, CẬP NHẬT hoặc XÓA dữ liệu khỏi các dạng xem tham chiếu dữ liệu từ nhiều bảng, ngoài ra còn có khả năng từ chối một phần của truy vấn hàng loạt và thực thi thành công một phần khác của lô đó. Không thể sử dụng trình kích hoạt INSTEAD OF với các dạng xem có thể cập nhật được CÓ CHỌN KIỂM TRA và trong các bảng có mối quan hệ tham chiếu chỉ định các hành động phân tầng trên DELETE hoặc UPDATE.

Sau khi thảo luận về các yếu tố kích hoạt về mặt lý thuyết, chúng ta sẽ bắt đầu trình bày những gì chúng ta thảo luận trên thực tế. Trong các bản trình diễn sắp tới, chúng tôi sẽ trình bày các tình huống khác nhau mà chúng tôi có thể tận dụng lợi ích từ các trình kích hoạt SQL Server.

SAU ... Trình kích hoạt DML

Giả sử rằng chúng ta cần theo dõi các hành động DML được thực hiện trên một bảng cụ thể và ghi các nhật ký này vào bảng lịch sử, nơi ID của bản ghi được chèn, cập nhật hoặc xóa và hành động được thực hiện sẽ được ghi vào bảng lịch sử. Các câu lệnh T-SQL CREATE TABLE bên dưới có thể được sử dụng để tạo cả bảng nguồn và bảng lịch sử:

 CREATE TABLE TriggerDemo_Parent (ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT) GOCREATE TABLE TriggerDemo_History (ID INT IDENTITY (1,1) PRIMARY KEY, ParentID INT , Thực hiện Hành động VARCHAR (50),) ĐI 

Để theo dõi thao tác INSERT, chúng tôi sẽ tạo một trình kích hoạt DML sẽ được kích hoạt sau khi thực hiện thao tác INSERT trên bảng mẹ. Trình kích hoạt này sẽ truy xuất giá trị ID được chèn cuối cùng vào bảng mẹ đó từ bảng được chèn ảo, như trong câu lệnh CREATE TRIGGER T-SQL bên dưới:

 TẠO TRIGGER AfterInsertTriggerON TriggerDemo_ParentAFTER INSERTASINSERT INTO TriggerDemo_History VALUES ((CHỌN TOP 1 được chèn. Đã chèn từ khóa), 'Chèn') ĐI 

Theo dõi hoạt động DELETE có thể đạt được bằng cách tạo một trình kích hoạt DML được kích hoạt sau khi thực hiện thao tác DELETE trên bảng mẹ. Một lần nữa, trình kích hoạt sẽ truy xuất giá trị ID của bản ghi bị xóa cuối cùng từ bảng mẹ đó từ bảng đã xóa ảo, như trong câu lệnh CREATE TRIGGER T-SQL bên dưới:

 TẠO TRIGGER AfterDeleteTriggerON TriggerDemo_ParentAFTER DELETEASINSERT INTO TriggerDemo_History VALUES ((CHỌN TOP 1 đã bị xóa. ID TỪ đã bị xóa), 'Xóa') ĐI 

Cuối cùng, chúng tôi cũng sẽ theo dõi hoạt động CẬP NHẬT bằng cách tạo trình kích hoạt DML sẽ được kích hoạt sau khi thực hiện thao tác CẬP NHẬT trên bảng mẹ. Trong trình kích hoạt này, chúng tôi sẽ truy xuất giá trị ID được cập nhật cuối cùng từ bảng mẹ đó từ bảng được chèn ảo, có lưu ý rằng quá trình CẬP NHẬT được thực hiện bằng cách xóa bản ghi và chèn bản ghi mới với các giá trị đã cập nhật, như trong CREATE TRIGGER Câu lệnh T-SQL bên dưới:

 TẠO TRIGGER AfterUPDATETriggerON TriggerDemo_ParentAFTER UPDATEASINSERT INTO TriggerDemo_History VALUES ((CHỌN ĐẦU 1 được chèn. Đã chèn từ khóa), 'CẬP NHẬT') ĐI 

Các bảng và trình kích hoạt hiện đã sẵn sàng cho quá trình thử nghiệm của chúng tôi. Nếu bạn cố gắng chèn một bản ghi mới vào bảng mẹ bằng cách sử dụng câu lệnh INSERT INTO T-SQL bên dưới:

 CHÈN VÀO TriggerDemo_Parent VALUES ('AAA', 'BBB', 500) 

Sau đó, bằng cách kiểm tra kế hoạch thực thi được tạo ra bằng cách thực hiện câu lệnh INSERT trước đó, bạn sẽ thấy rằng hai hoạt động chèn sẽ được thực hiện, ảnh hưởng đến hai bảng; bảng mẹ với các giá trị được chỉ định trong câu lệnh INSERT và bảng lịch sử do kích hoạt trình kích hoạt SAU KHI CHÈN, như được hiển thị trong kế hoạch thực thi bên dưới:

Nó cũng rõ ràng khi bạn kiểm tra dữ liệu được chèn vào cả bảng cha và bảng lịch sử bằng cách sử dụng các câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_ParentGOSELECT * TỪ TriggerDemo_History 

Nơi các giá trị được chỉ định trong câu lệnh INSERT sẽ được chèn vào bảng mẹ và nhật ký chèn chứa ID của bản ghi đã chèn và thao tác được thực hiện sẽ được chèn vào bảng lịch sử, như được hiển thị trong kết quả bên dưới:

Bây giờ, nếu bạn cố gắng cập nhật bản ghi hiện có trong bảng mẹ bằng cách sử dụng câu lệnh UPDATE T-SQL bên dưới:

 CẬP NHẬT TriggerDemo_Parent SET Emp_Salary =550 WHERE ID =1 

Và kiểm tra kế hoạch thực thi được tạo ra bằng cách thực hiện câu lệnh UPDATE trước đó, bạn sẽ thấy rằng hoạt động cập nhật sẽ được theo sau bởi một hoạt động chèn ảnh hưởng đến hai bảng khác nhau; bảng mẹ sẽ được cập nhật với giá trị được chỉ định trong câu lệnh UPDATE và thao tác chèn vào bảng lịch sử do kích hoạt trình kích hoạt SAU KHI CẬP NHẬT, như được hiển thị trong kế hoạch thực thi bên dưới:

Kiểm tra cả bản ghi mẹ và bảng lịch sử bằng cách sử dụng các câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_ParentGOSELECT * TỪ TriggerDemo_History 

Bạn sẽ thấy rằng câu lệnh cập nhật sẽ sửa đổi giá trị Emp_Salary trong bảng mẹ với giá trị được chỉ định trong câu lệnh UPDATE và nhật ký cập nhật có chứa ID của bản ghi cập nhật và thao tác được thực hiện sẽ được chèn vào bảng lịch sử, như hiển thị trong kết quả bên dưới:

Trong kịch bản cuối cùng của trình kích hoạt SAU DML, chúng tôi sẽ theo dõi việc xóa bản ghi hiện có khỏi bảng mẹ bằng cách sử dụng câu lệnh DELETE T-SQL bên dưới:

 XÓA khỏi TriggerDemo_Parent WHERE ID =1 

Sau đó kiểm tra kế hoạch thực thi được tạo ra bằng cách thực hiện câu lệnh DELETE trước đó, bạn sẽ thấy rằng hoạt động DELETE sẽ được theo sau bởi hoạt động chèn, ảnh hưởng đến hai bảng khác nhau; bảng mẹ mà từ đó bản ghi có ID được cung cấp trong mệnh đề WHERE của câu lệnh DELETE sẽ bị xóa và thao tác chèn vào bảng lịch sử do kích hoạt trình kích hoạt SAU KHI XÓA, như được hiển thị trong kế hoạch thực thi bên dưới:

Nếu bạn kiểm tra cả bản ghi gốc và bản ghi bảng lịch sử bằng cách sử dụng câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_ParentGOSELECT * TỪ TriggerDemo_History 

Bạn sẽ thấy rằng bản ghi có giá trị ID bằng 1 đã bị xóa khỏi bảng mẹ được cung cấp trong câu lệnh DELETE và nhật ký xóa có chứa ID của bản ghi đã xóa và thao tác được thực hiện sẽ được chèn vào bảng lịch sử , như được hiển thị trong kết quả bên dưới:

INSTEAD OF… DML Trigger

Loại trình kích hoạt DML thứ hai là trình kích hoạt INSTEAD OF DML. Như đã đề cập trước đó, trình kích hoạt INSTEAD OF sẽ ghi đè câu lệnh của hành động kích hoạt trình kích hoạt bằng câu lệnh được cung cấp trong trình kích hoạt. Giả sử rằng chúng ta cần ghi nhật ký các hành động DML mà người dùng đang cố gắng thực hiện trên một bảng cụ thể mà không cho phép họ thực hiện hành động đó. Các câu lệnh T-SQL CREATE TABLE bên dưới có thể được sử dụng để tạo cả bảng nguồn và bảng thay thế:

 CREATE TABLE TriggerDemo_NewParent (ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT) GOCREATE TABLE TriggerDemo_InsteadParent (ID INT IDENTITY (1,1) PRIMARY INT KEY , Thực hiện Hành động VARCHAR (50),) ĐI 

Sau khi tạo hai bảng, chúng tôi sẽ chèn một bản ghi vào bảng nguồn cho bản trình diễn của chúng tôi bằng cách sử dụng câu lệnh INSERT INTO bên dưới:

 CHÈN VÀO TriggerDemo_NewParent VALUES ('AA', 'BB', 500) 

Đối với bản trình diễn này, chúng tôi sẽ tạo ba trình kích hoạt để ghi đè các hoạt động CHÈN, CẬP NHẬT và XÓA. Trình kích hoạt đầu tiên sẽ được sử dụng để ngăn chặn bất kỳ thao tác chèn nào trên bảng mẹ và nhật ký thay đổi vào bảng thay thế. Trình kích hoạt được tạo bằng cách sử dụng câu lệnh CREATE TRIGGER T-SQL bên dưới:

 TẠO TRIGGER Thay vào đóOfInsertTriggerON TriggerDemo_NewParentINSTEAD OF INSERTASINSERT INTO TriggerDemo_InsteadParent VALUES ((CHỌN TOP 1 được chèn. Đã chèn ID FROM), 'Đang cố gắng Chèn ID mới') ĐI 

Trình kích hoạt thứ hai được sử dụng để ngăn bất kỳ thao tác cập nhật nào trên bảng mẹ và nhật ký thay đổi thành bảng thay thế. Trình kích hoạt này được tạo như bên dưới:

 TẠO TRIGGER ReplaceOfUpdateTriggerON TriggerDemo_NewParentINSTEAD OF UPDATEASINSERT INTO TriggerDemo_InsteadParent VALUES ((CHỌN TOP 1 được chèn. ID FROM đã được chèn), 'Đang cố gắng cập nhật ID hiện có') ĐI 

Kích hoạt cuối cùng sẽ được sử dụng để ngăn chặn bất kỳ thao tác xóa nào trên bảng mẹ và nhật ký thay đổi thành bảng thay thế. Trình kích hoạt này được tạo như sau:

 TẠO TRIGGER Thay vào đóOfDeleteTriggerON TriggerDemo_NewParentINSTEAD OF DELETEASINSERT INTO TriggerDemo_InsteadParent VALUES ((CHỌN TOP 1 được chèn. ID FROM đã được chèn), 'Đang cố gắng xóa ID hiện có') ĐI 

Hai bảng và ba trình kích hoạt đã sẵn sàng. Nếu bạn cố gắng chèn một giá trị mới vào bảng mẹ bằng cách sử dụng câu lệnh INSERT INTO T-SQL bên dưới:

 CHÈN VÀO TriggerDemo_NewParent VALUES ('CCC', 'DDD', 500) 

Sau đó, kiểm tra cả bản ghi bảng cha và bảng thay thế bằng cách sử dụng các câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_NewParentGOSELECT * TỪ TriggerDemo_InsteadParent 

Do thực tế là chúng ta có kích hoạt INSTEAD OF INSERT trong bảng mẹ, bạn sẽ thấy từ kết quả rằng không có bản ghi mới nào được chèn vào bảng mẹ và nhật ký cho thao tác chèn được chèn vào bảng thay thế, như được hiển thị trong kết quả bên dưới:

Đang cố gắng cập nhật bản ghi hiện có trong bảng mẹ bằng cách sử dụng câu lệnh UPDATE T-SQL bên dưới:

 CẬP NHẬT TriggerDemo_NewParent SET Emp_Salary =550 WHERE ID =1 

Sau đó, kiểm tra cả bản ghi bảng cha và bảng thay thế bằng cách sử dụng các câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_NewParentGOSELECT * TỪ TriggerDemo_InsteadParent 

Bạn sẽ thấy từ kết quả rằng giá trị Emp_Salary của bản ghi có giá trị ID bằng 1 từ bảng mẹ sẽ không bị thay đổi và nhật ký cho thao tác cập nhật được chèn vào bảng thay thế do có kích hoạt INSTEAD OF UPDATE trong bảng cha, như được hiển thị trong kết quả bên dưới:

Cuối cùng, nếu chúng tôi cố gắng xóa một bản ghi hiện có khỏi bảng mẹ bằng cách sử dụng câu lệnh DELETE T-SQL bên dưới:

 XÓA khỏi TriggerDemo_NewParent WHERE ID =1 

Và kiểm tra cả bản ghi bảng cha và bảng thay thế bằng cách sử dụng các câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_NewParentGOSELECT * TỪ TriggerDemo_InsteadParent 

Kết quả sẽ rõ ràng là bản ghi có giá trị ID bằng 1 từ bảng mẹ sẽ không bị xóa và nhật ký cho thao tác xóa được chèn vào bảng thay thế do có kích hoạt INSTEAD OF DELETE trong bảng mẹ. bảng, như được hiển thị trong kết quả bên dưới:

SAU ... Kích hoạt DML với Tin nhắn

Trình kích hoạt SAU cũng có thể được sử dụng để đưa ra thông báo cảnh báo cho người dùng. Trong trường hợp này, truy vấn sẽ là một thông báo cung cấp thông tin sẽ không ngăn cản việc thực thi câu lệnh kích hoạt trình kích hoạt. Hãy để chúng tôi loại bỏ trình kích hoạt INSTEAD OF UPDATE đã tạo trước đó và thay thế nó bằng một trình kích hoạt SAU KHI CẬP NHẬT khác sẽ gây ra lỗi cảnh báo sau khi thực hiện bất kỳ thao tác cập nhật nào bằng cách sử dụng câu lệnh T-SQL DROP / CREATE TRIGGER bên dưới:

 DROP TRIGGER ReplaceOfUpdateTriggerCREATE TRIGGER ReminderTrigger ON TriggerDemo_NewParent SAU KHI CẬP NHẬT NHƯ RAISERROR ('Cập nhật được thực hiện trên bảng TriggerDemo_NewParent', 16, 10); ĐI 

Nếu bạn cố gắng cập nhật giá trị Emp_Salary của nhân viên với giá trị ID bằng 1 bằng cách sử dụng câu lệnh UDPATE bên dưới:

 CẬP NHẬT TriggerDemo_NewParent SET Emp_Salary =550 WHERE ID =1 

Thông báo lỗi sẽ xuất hiện trong Tin nhắn , có chứa thông báo được cung cấp trong trình kích hoạt đã tạo, như được hiển thị bên dưới:

Kiểm tra dữ liệu bảng mẹ bằng cách sử dụng câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_NewParent 

Từ kết quả, bạn sẽ thấy Emp_Salary được cập nhật thành công, như hình dưới đây:

Nếu bạn cần trình kích hoạt SAU KHI CẬP NHẬT để dừng hoạt động cập nhật sau khi đưa ra thông báo lỗi, thì QUAY LẠI câu lệnh có thể được thêm vào trình kích hoạt để khôi phục hoạt động cập nhật đã kích hoạt trình kích hoạt đó, nhắc lại rằng trình kích hoạt và câu lệnh kích hoạt trình kích hoạt sẽ được thực hiện trong cùng một giao dịch. Điều này có thể đạt được bằng cách sử dụng câu lệnh ALTER TRIGGER T-SQL, xem:

 ALTER TRIGGER ReminderTrigger TRÊN TriggerDemo_NewParent SAU KHI CẬP NHẬT AS RAISERROR ('Cập nhật được thực hiện trên bảng TriggerDemo_NewParent', 16, 10); ROLLBACKGO 

Nếu bạn cố gắng cập nhật giá trị Emp_Salary của nhân viên có ID bằng 1 bằng cách sử dụng câu lệnh UPDATE bên dưới:

 CẬP NHẬT TriggerDemo_NewParent SET Emp_Salary =700 WHERE ID =1 

Một lần nữa, thông báo lỗi sẽ được hiển thị trong Tin nhắn nhưng lần này, thao tác cập nhật sẽ được khôi phục hoàn toàn, như được hiển thị trong thông báo lỗi bên dưới:

Kiểm tra giá trị từ bảng nguồn bằng cách sử dụng câu lệnh SELECT bên dưới:

 CHỌN * TỪ TriggerDemo_NewParent 

Bạn sẽ thấy rằng giá trị Emp_Salary không thay đổi, vì trình kích hoạt SAU KHI CẬP NHẬT đã khôi phục toàn bộ giao dịch sau khi tăng thông báo lỗi, như được hiển thị trong kết quả bảng bên dưới:

Nhược điểm của trình kích hoạt

Với tất cả những ưu điểm đã đề cập của trình kích hoạt SQL Server, trình kích hoạt làm tăng độ phức tạp của cơ sở dữ liệu. Nếu trình kích hoạt được thiết kế sai hoặc sử dụng quá mức, nó sẽ dẫn đến các vấn đề lớn về hiệu suất, chẳng hạn như các phiên bị chặn, do kéo dài tuổi thọ của giao dịch trong thời gian dài hơn, chi phí tăng thêm trên hệ thống do thực hiện nó mỗi lần CHÈN, CẬP NHẬT hoặc Hành động DELETE được thực hiện hoặc nó có thể dẫn đến sự cố mất dữ liệu. Ngoài ra, không dễ dàng để xem và theo dõi các kích hoạt cơ sở dữ liệu, đặc biệt nếu không có tài liệu về nó vì nó vô hình đối với các nhà phát triển và ứng dụng.

Các giải pháp thay thế kích hoạt… Thực thi tính toàn vẹn

Nếu phát hiện thấy các trình kích hoạt đang gây hại cho hiệu suất của phiên bản SQL Server của bạn, bạn phải thay thế chúng bằng các giải pháp khác. Ví dụ:thay vì sử dụng trình kích hoạt để thực thi tính toàn vẹn của thực thể, nó nên được thực thi ở cấp thấp nhất bằng cách sử dụng các ràng buộc CHÍNH và UNIQUE. Điều tương tự cũng được áp dụng cho tính toàn vẹn của miền cần được thực thi thông qua các ràng buộc CHECK và tính toàn vẹn tham chiếu sẽ được thực thi thông qua các ràng buộc NGOẠI KHÓA. Bạn chỉ có thể sử dụng trình kích hoạt DML nếu các tính năng được hỗ trợ bởi một ràng buộc cụ thể không thể đáp ứng các yêu cầu ứng dụng của bạn.

Hãy để chúng tôi so sánh giữa việc thực thi tính toàn vẹn của miền bằng cách sử dụng trình kích hoạt DML và sử dụng các ràng buộc KIỂM TRA. Giả sử rằng chúng ta cần thực thi chỉ chèn các giá trị dương vào cột Emp_Salary. Chúng ta sẽ bắt đầu với việc tạo một bảng đơn giản bằng câu lệnh CREATE TABLE T-SQL bên dưới:

 TẠO BẢNG EmployeeSalaryTrigger (ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT) ĐI 

Sau đó, xác định trình kích hoạt SAU KHI CHÈN DML đảm bảo rằng bạn chèn giá trị dương vào cột Emp_Salary bằng cách quay ngược giao dịch nếu người dùng chèn giá trị lương âm, sử dụng câu lệnh CREATE TRIGGER T-SQL bên dưới:

 TẠO TRIGGER TRGR_EFasteeSalary TRÊN EmployeeSalaryTrigger SAU KHI CHÈN ASDECLARE @EmpSal AS INTSET @EmpSal =(Đã chèn CHỌN ĐẦU 1. Đã chèn Emp_Salary FROM) IF @EmpSal <0BEGIN RAISERROR ('Không thể chèn lương âm', 16,10); ROLLBACKEND 

Đối với mục đích so sánh, chúng tôi sẽ tạo một bảng đơn giản khác, với cùng một lược đồ và xác định ràng buộc KIỂM TRA trong câu lệnh CREATE TABLE để chỉ chấp nhận các giá trị dương trong cột Emp_Salary, như được hiển thị bên dưới:

 TẠO BẢNG 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)) ĐI 

Nếu bạn cố gắng chèn bản ghi bên dưới có chứa giá trị Emp_Salary âm vào bảng đầu tiên có trình kích hoạt được xác định trước, hãy sử dụng câu lệnh INSERT INTO bên dưới:

 CHÈN VÀO CÁC GIÁ TRỊ CỦA EmployeeSalaryTrigger ('Ali', 'Fadi', - 4) ĐI 

Câu lệnh INSERT sẽ không đưa ra được thông báo lỗi cho thấy rằng bạn không thể chèn giá trị âm vào cột Emp_Salary và khôi phục toàn bộ giao dịch do có trình kích hoạt SAU KHI CHÈN, như được hiển thị trong thông báo lỗi bên dưới:

Ngoài ra, nếu bạn cố gắng chèn cùng một bản ghi có chứa giá trị Emp_Salary âm vào bảng thứ hai có ràng buộc CHECK được xác định trước bằng cách sử dụng câu lệnh INSERT INTO bên dưới:

 CHÈN VÀO GIÁ TRỊ EmployeeSalaryConstraint ('Ali', 'Fadi', - 4) 

Câu lệnh INSERT sẽ lại không thành công cho thấy rằng bạn đang cố chèn giá trị xung đột với điều kiện ràng buộc CHECK, như được hiển thị trong thông báo lỗi bên dưới:

Từ các kết quả trước đó, bạn thấy rằng cả phương thức kích hoạt và ràng buộc CHECK đều đạt được mục tiêu bằng cách ngăn bạn chèn các giá trị Emp_Salary âm. Nhưng cái nào thì tốt hơn? Hãy để chúng tôi so sánh hiệu suất của hai phương pháp bằng cách kiểm tra trọng số kế hoạch thực thi cho mỗi phương pháp. Từ các kế hoạch thực thi đã tạo sau khi thực hiện hai truy vấn, bạn sẽ thấy rằng trọng số của phương thức kích hoạt là ba lần trọng số của phương thức ràng buộc CHECK, như được hiển thị trong so sánh kế hoạch thực thi bên dưới:

Ngoài ra, để so sánh thời gian thực thi của từng cái, chúng ta hãy chạy mỗi cái 1000 lần bằng cách sử dụng các câu lệnh T-SQL bên dưới:

 CHÈN VÀO GIÁ TRỊ NHÂN VIÊN 

Bạn sẽ thấy rằng phương pháp đầu tiên đang sử dụng trình kích hoạt sẽ mất khoảng 31 mili giây được thực thi hoàn toàn, trong đó phương thức thứ hai đang sử dụng ràng buộc CHECK sẽ chỉ mất 17ms , khoảng 0,5 lần yêu cầu trong phương pháp sử dụng trình kích hoạt. Điều này là do trình kích hoạt sẽ kéo dài tuổi thọ giao dịch và sẽ khôi phục truy vấn kích hoạt trình kích hoạt sau khi thực thi khi phát hiện thấy vi phạm tính toàn vẹn, gây ra sự suy giảm hiệu suất do quá trình khôi phục. Trường hợp khác khi sử dụng ràng buộc CHECK, trong đó ràng buộc sẽ thực hiện công việc của nó trước khi thực hiện bất kỳ sửa đổi nào trong dữ liệu, không yêu cầu khôi phục trong trường hợp vi phạm.

Các giải pháp thay thế kích hoạt… Kiểm toán

Như chúng tôi đã đề cập trước đây, các trình kích hoạt cũng có thể được sử dụng để kiểm tra và theo dõi các thay đổi được thực hiện trên một bảng cụ thể. Nếu phương pháp kiểm tra này gây ra sự suy giảm hiệu suất trong phiên bản SQL Server của bạn, bạn có thể dễ dàng thay thế nó bằng OUTPUT mệnh đề. Mệnh đề OUTPUT trả về thông tin về mỗi hàng bị ảnh hưởng bởi thao tác INSERT, UPDATE hoặc DELETE, dưới dạng một thông báo xác nhận hoặc một giá trị có thể được chèn vào bảng lịch sử. Phương thức mệnh đề OUTPUT cũng cung cấp cho chúng tôi nhiều quyền kiểm soát hơn đối với mã được thực thi, vì nó sẽ được thêm vào chính câu lệnh chèn, sửa đổi hoặc xóa dữ liệu bất cứ khi nào bạn muốn, ngược lại với trình kích hoạt sẽ luôn được thực thi.

Hãy để chúng tôi so sánh giữa ghi nhật ký việc chèn và sửa đổi dữ liệu vào bảng lịch sử bằng cách sử dụng trình kích hoạt DML và sử dụng mệnh đề OUTPUT. Chúng ta sẽ bắt đầu với việc tạo bảng lịch sử và sản xuất bên dưới bằng cách sử dụng câu lệnh T-SQL CREATE TABLE TABLE bên dưới:

 TẠO BẢNG TriggerDemo_Prod (ID INT IDENTITY (1,1) KHÓA CHÍNH, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT) BẢNG GOCREATE TriggerDemo_ProdHistory (ID INT IDENTITY (1,1) KHÓA CHÍNH , Hoang đàng INT, TS DATETIME,) ĐI 

Khi cả hai bảng được tạo thành công, chúng tôi sẽ tạo trình kích hoạt SAU KHI CHÈN, CẬP NHẬT DML sẽ ghi một bản ghi vào bảng lịch sử nếu bất kỳ hàng mới nào được chèn vào bảng sản xuất hoặc bản ghi hiện có được sửa đổi bằng cách sử dụng câu lệnh CREATE TRIGGER T-SQL dưới đây:

 TẠO TRIGGER ProdHistoryON TriggerDemo_ProdAFTER INSERT, UPDATEASINSERT INTO TriggerDemo_ProdHistory VALUES ((CHỌN TOP 1 được chèn. ID FROM đã chèn), (CHỌN TOP 1 được chèn. Đã chèn Emp_Salary FROM), GETDATE ()) ĐI 

Để so sánh việc ghi nhật ký các thay đổi bằng cách sử dụng phương thức trình kích hoạt và mệnh đề OUTPUT, chúng ta cần tạo hai bảng đơn giản mới, bảng sản xuất và bảng lịch sử, với cùng một lược đồ như hai bảng trước, nhưng lần này không xác định trình kích hoạt, sử dụng TẠO BẢNG Câu lệnh T-SQL bên dưới:

 CREATE TABLE OutputDemo_Prod (ID INT IDENTITY (1,1) PRIMARY KEY, Emp_First_name VARCHAR (50), Emp_Last_name VARCHAR (50), Emp_Salary INT) GOCREATE TABLE OutputDemo_ProdHistory (ID INT IDENTITY (1,1) PRIMARY KEY, ProdID INT , Hoang đàng INT, TS DATETIME,) ĐI 

Bây giờ bốn bảng đã sẵn sàng để thử nghiệm. Chúng tôi sẽ chèn một bản ghi vào bảng sản xuất đầu tiên có trình kích hoạt bằng cách sử dụng câu lệnh INSERT INTO T-SQL bên dưới:

 CHÈN VÀO các giá trị TriggerDemo_Prod ('AA', 'BB', 750) ĐI 

Sau đó, chúng tôi sẽ chèn cùng một bản ghi vào bảng sản xuất thứ hai bằng cách sử dụng mệnh đề OUTPUT. Câu lệnh INSERT INTO dưới đây sẽ hoạt động như hai câu lệnh chèn; câu lệnh đầu tiên sẽ chèn cùng một bản ghi vào bảng sản xuất và câu lệnh chèn thứ hai bên cạnh mệnh đề OUTPUT sẽ chèn nhật ký chèn vào bảng lịch sử:

 INSERT INTO OutputDemo_Prod OUTPUT được chèn.ID, đã chèn.Emp_Salary, GETDATE () INTO OutputDemo_ProdHistory giá trị ('AA', 'BB', 750) ĐI 

Kiểm tra dữ liệu được chèn vào bốn bảng sản xuất và lịch sử, bạn sẽ thấy rằng cả hai phương thức, phương thức kích hoạt và OUTPUT, sẽ ghi cùng một nhật ký vào bảng lịch sử thành công và theo cùng một cách, như được hiển thị trong kết quả bên dưới:

Từ các kế hoạch thực thi đã tạo sau khi thực hiện hai truy vấn, bạn sẽ thấy rằng trọng số của phương thức kích hoạt là khoảng (21% + 36%) 57% trọng lượng tổng thể, trong đó trọng số của phương pháp OUTPUT là khoảng 43% , với sự khác biệt về trọng lượng nhỏ, như được thể hiện trong so sánh kế hoạch thực hiện bên dưới:

Sự khác biệt về hiệu suất rõ ràng khi so sánh thời gian thực thi được sử dụng bởi từng phương pháp, trong đó việc ghi nhật ký các thay đổi bằng phương pháp kích hoạt sẽ tiêu tốn (114 + 125) 239 mili giây được thực thi hoàn toàn và phương thức đang sử dụng phương thức mệnh đề OUTPUT chỉ tiêu tốn 5ms , là 2% thời gian được sử dụng trong phương pháp kích hoạt, như được hiển thị rõ ràng từ Thống kê thời gian bên dưới:

Từ kết quả trước đó, rõ ràng là sử dụng phương pháp OUTPUT tốt hơn so với sử dụng trình kích hoạt để kiểm tra các thay đổi.

Liên kết hữu ích:

  • TẠO TRIGGER (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql
  • Trình kích hoạt DML https://docs.microsoft.com/en-us/sql/relational-databases/triggers/dml-triggers
  • Trình kích hoạt DDL https://docs.microsoft.com/en-us/sql/relational-databases/triggers/ddl-triggers
  • Điều khoản OUTPUT (Transact-SQL) https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách tính tổng số giờ đi lại giữa thành phố x, y và ngược lại

  2. SqlServer:Đăng nhập không thành công cho người dùng

  3. Cách kiểm tra cài đặt ANSI_NULLS của phiên trong SQL Server

  4. Kết nối với SQL Server thông qua PDO bằng SQL Server Driver

  5. Cập nhật Dữ liệu Salesforce bằng Con trỏ Máy chủ SQL