0Pricing
SQL Academy · 课时

使用触发器审计表

使用将记录写入 audit_log 表的 AFTER INSERT/UPDATE/DELETE 触发器构建审计轨迹

使用触发器审计表 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。

为什么需要审计

审计日志可以回答“谁在什么时候更改了什么”。合规要求(HIPAA、SOX、GDPR 的被遗忘权调查)和运营取证都需要它。

审计表

一个中心表记录每项更改:

CREATE TABLE audit_log (
  id BIGSERIAL PRIMARY KEY,
  ts TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  user_name TEXT NOT NULL DEFAULT CURRENT_USER,
  table_name TEXT NOT NULL,
  action TEXT NOT NULL,             -- INSERT, UPDATE, DELETE
  row_id TEXT,
  old_data JSONB,
  new_data JSONB
);

审计触发器函数

一个函数即可在多个表之间重复使用:

CREATE OR REPLACE FUNCTION audit_row()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO audit_log (table_name, action, row_id, old_data, new_data)
  VALUES (
    TG_TABLE_NAME,
    TG_OP,
    COALESCE(NEW.id::TEXT, OLD.id::TEXT),
    CASE WHEN TG_OP IN ('UPDATE','DELETE') THEN to_jsonb(OLD) END,
    CASE WHEN TG_OP IN ('INSERT','UPDATE') THEN to_jsonb(NEW) END
  );
  RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

附加到表

在 AFTER INSERT/UPDATE/DELETE 时触发:

CREATE TRIGGER trg_audit_users
AFTER INSERT OR UPDATE OR DELETE ON users
FOR EACH ROW EXECUTE FUNCTION audit_row();

to_jsonb(NEW)

to_jsonb 技巧可以通用地捕获整行数据——无需为每一列编写代码。它适用于任何包含 id 列的表。

跟踪操作者

如果应用使用单个数据库用户运行,仅靠 CURRENT_USER 并不足够。请通过会话 GUC 传递应用用户:

-- App sets:
SET LOCAL app.user_id = '42';

-- Trigger reads:
INSERT INTO audit_log (... actor_id ...) VALUES (..., current_setting('app.user_id', true)::BIGINT);

审计特定列

使用触发器 WHEN 子句进行选择性审计:

CREATE TRIGGER trg_audit_role_change
AFTER UPDATE OF role ON users
FOR EACH ROW WHEN (OLD.role IS DISTINCT FROM NEW.role)
EXECUTE FUNCTION audit_role_change();

每表一个审计表

另一种方案是为每个实际表使用一个审计表(例如 users_audit),并保留相同的架构及审计元数据。这样更容易查询,但需要维护更多 DDL。

仅审计差异

仅存储发生更改的列:

INSERT INTO audit_log (table_name, action, changes)
VALUES (
  TG_TABLE_NAME, TG_OP,
  (SELECT jsonb_object_agg(key, value)
   FROM jsonb_each(to_jsonb(NEW))
   WHERE NEW.* IS DISTINCT FROM OLD.* AND to_jsonb(NEW)->key IS DISTINCT FROM to_jsonb(OLD)->key)
);

审计表性能

在繁忙系统中,审计表会快速增长。请按时间进行分区:

CREATE TABLE audit_log (...) PARTITION BY RANGE (ts);
CREATE TABLE audit_log_2024_q1 PARTITION OF audit_log
  FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');

性能权衡

现在每次插入、更新或删除都会额外写入一行。对于写入极其频繁的表,这可能会使输入/输出翻倍。请进行测试和监控,然后决定这种权衡是否值得。

何时不应使用数据库触发器

如果您需要与事件总线集成,请使用 NOTIFY 或 LISTEN 将事件排入队列,或者使用逻辑复制 / CDC 工具(Debezium),而不是触发器。

回顾

审计触发器是捕获历史记录的最简单方式。

  • 使用 to_jsonb(NEW/OLD) 的通用函数
  • 附加到每个需要审计的表
  • 按时间对审计表进行分区
  • 通过 GUC 显式跟踪应用操作者

快速检查

在审计触发器函数中,如何通用地将新行捕获为 JSONB?

常见问题解答

「使用触发器审计表」课时是免费的吗?

是的 — 「使用触发器审计表」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。

「使用触发器审计表」这节课中我会学到什么?

使用将记录写入 audit_log 表的 AFTER INSERT/UPDATE/DELETE 触发器构建审计轨迹 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「使用触发器审计表」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Academy 课中编写并运行代码吗?

能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 触发器剖析:BEFORE/AFTER、FOR EACH ROW
  2. PL/pgSQL 函数基础
  3. DO 块与匿名代码
  4. 使用触发器审计表
← 返回 SQL Academy