编程数据库工程师 / DBA

解释SQL触发器的工作原理,它们的优缺点,以及典型的使用场景。请举例说明真实的触发器。

用 Hintsage AI 助手通过面试

答复

触发器是特殊的数据库对象,当在表上发生INSERT、UPDATE或DELETE事件时,会自动执行特定代码(通常是SQL或过程扩展语言,例如PostgreSQL的PL/pgSQL)。

优点:

  • 集中应用业务逻辑和数据验证。
  • 自动化审计(例如,变更历史)。

缺点:

  • 隐式执行——并不总是显而易见触发器是否被执行。
  • 当表频繁更改时,性能下降。
  • 调试和调试困难,存在循环触发的风险(递归触发器)。
  • 数据迁移变得更加复杂。

何时使用:

  • 数据审计。
  • 自动创建关联记录。
  • 实现标准方法无法满足的约束控制。

触发器示例(PostgreSQL):

CREATE TABLE employee_audit ( id SERIAL PRIMARY KEY, employee_id INT, old_salary NUMERIC, new_salary NUMERIC, changed_at TIMESTAMP ); CREATE OR REPLACE FUNCTION audit_salary() RETURNS TRIGGER AS $$ BEGIN IF NEW.salary <> OLD.salary THEN INSERT INTO employee_audit(employee_id, old_salary, new_salary, changed_at) VALUES (OLD.id, OLD.salary, NEW.salary, NOW()); END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_salary_update AFTER UPDATE ON employees FOR EACH ROW EXECUTE FUNCTION audit_salary();

有陷阱的问题

可以在触发器内更新同一张表吗?会发生什么?

答复:
如果触发器设置为表的UPDATE事件,并且在内部执行该同一表的另一个UPDATE,这将导致无限递归(循环)并导致命令异常结束或触发器深度溢出错误。因此,请始终控制以避免递归,或者使用允许/禁止递归调用的选项。

示例:

-- 这种结构可能会导致触发器循环: CREATE OR REPLACE FUNCTION recursive_update() RETURNS TRIGGER AS $$ BEGIN UPDATE employees SET salary = salary * 1.01 WHERE id = NEW.id; -- 将再次触发 RETURN NEW; END; $$ LANGUAGE plpgsql;

历史

在会计CRM中引入了触发器,以便在更改交易表时自动记录操作。高负载下,服务速度减慢,分析表明:触发器在插入日志中耗费了大量时间且未经过优化(例如,仅记录重要事件)。


历史

在库存管理项目中使用了BEFORE INSERT触发器来计算项目ID。错误的ID逻辑导致数据重复,错误在很长时间内未被发现,因为它在“后台”运行。


历史

在HR平台中,触发器在每次INSERT时会对父表和子表进行批量更新。由于触发器逻辑错误,引发递归,完全阻塞了所有与表的操作。不得不禁用触发器并进行复杂的回滚操作以解锁表。