🎯 Một góc nhìn thực tế với DDL Trigger – Giữ vững “kỷ luật” hệ thống!
Sau 2 phần đầu nói về DML Trigger – chuyên theo dõi dữ liệu (orders, order_detail) thì hôm nay mình muốn chia sẻ một loại trigger cũng “ngầu không kém” nhưng lại ít được khai thác: DDL Trigger.
💡 DDL Trigger là gì?
Nếu bạn ví hệ thống dữ liệu là “ngôi nhà”, thì DML Trigger là người theo dõi hành vi trong nhà (ai thêm sửa xóa gì trong data), còn DDL Trigger là hệ thống camera an ninh gắn quanh nhà – để phát hiện ai động vào cấu trúc hệ thống: tạo bảng mới, drop bảng, sửa stored procedure,…
Với team làm Product như mình, data và cấu trúc là "xương sống". Từ đó mình luôn giữ một DDL Trigger để giám sát chặt các thay đổi cấu trúc hệ thống.
🧰 Bảng lưu log DDL: ddl_change_log
Vì code công ty không được public nên mình dựng một ví dụ tương tự:
Tạo table chứa log
CREATE TABLE [dbo].[ddl_change_log]
( [id] [int] NOT NULL IDENTITY(1, 1), [database_name] [nvarchar] (256) NULL, [schema_name] [nvarchar] (128) NULL, [event_type] [nvarchar] (128) NULL, [event_ddl] [nvarchar] (max) NULL, [event_xml] [xml] NULL, [object_name] [nvarchar] (256) NULL, [object_type] [nvarchar] (128) NULL, [host_name] [nvarchar] (128) NULL, [ip_address] [varchar] (64) NULL, [program_name] [nvarchar] (256) NULL, [login_name] [nvarchar] (256) NULL, [created_date] [datetime] NULL DEFAULT (getdate())
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE [dbo].[ddl_change_log] ADD PRIMARY KEY CLUSTERED ([id]) ON [PRIMARY]
GO
Tạo DDL Trigger: trg_TrackDDLChanges
CREATE TRIGGER trg_TrackDDLChanges
ON DATABASE
FOR ALTER_SCHEMA, DROP_SCHEMA, ALTER_TABLE, DROP_TABLE, ALTER_INDEX, DROP_INDEX, ALTER_VIEW, DROP_VIEW, ALTER_TRIGGER, DROP_TRIGGER, ALTER_PROCEDURE, DROP_PROCEDURE, ALTER_FUNCTION, DROP_FUNCTION
AS
--==========================================
-- Author: Nguyễn Kim Duy
-- Created on: 07/04/2025
-- Description: --==========================================
BEGIN DECLARE @eventData XML = EVENTDATA(); INSERT dbo.ddl_change_log ( database_name, schema_name, event_type, event_ddl, event_xml, object_name, object_type, host_name, ip_address, program_name, login_name ) SELECT DB_NAME(), @eventData.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)'), @eventData.value('(/EVENT_INSTANCE/EventType)[1]', 'NVARCHAR(128)'), @eventData.value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]', 'NVARCHAR(MAX)'), @eventData, @eventData.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(256)'), @eventData.value('(/EVENT_INSTANCE/ObjectType)[1]', 'NVARCHAR(128)'), CONVERT(NVARCHAR(128), HOST_NAME()), CONVERT(NVARCHAR(64), CONNECTIONPROPERTY('client_net_address')), CONVERT(NVARCHAR(256), PROGRAM_NAME()), CONVERT(NVARCHAR(256), SYSTEM_USER);
END;
GO
Mình tạo 1 table để test nhé.
CREATE TABLE dbo.TestTrigger ( ID INT IDENTITY(1,1), Name NVARCHAR(50)
);
Cùng mình thử và xem kết quả nhé.
1. Mình sẽ thêm 1 cột 'Description' vào table dbo.TestTrigger
2. Mình sẽ xóa table dbo.TestTrigger
3.Tương tự SCHEMA, INDEX, VIEW, TRIGGER, FUNCTION. Các bạn tự kiểm thử tiếp nhé.
📌 Mỗi khi có ai thực hiện CREATE, ALTER, DROP,… thì bạn sẽ biết:
- Ai làm (LoginName)
- Tác động gì (EventType)
- Tác động lên đâu (ObjectName, ObjectType)
- Từ đâu (HostName, IPAddress, ProgramName)
- Nội dung SQL là gì (EventDDL)
- Khi nào (CreatedDate)
🛡️ Lợi ích thực tế
- 📌 Giúp phát hiện ai đang tác động vào schema
- 🔎 Truy tìm lỗi nhanh khi “bỗng dưng mất bảng”
- 🧠 Ghi lại lịch sử để audit hoặc truy vết
- ☁️ Kết hợp gửi email cảnh báo nếu muốn proactive hơn
🧩 Tổng kết
Với mình, Trigger không còn là kiến thức trường lớp, mà là công cụ đầy thực dụng để kiểm soát hệ thống. Dù là DML hay DDL – đúng nơi, đúng thời điểm – thì Trigger vẫn là vũ khí đáng giá 💥
📣 Bạn đã từng dùng DDL Trigger chưa? Hay có tình huống nào mà Trigger đã “cứu” bạn một bàn thua trông thấy?