加入收藏 | 设为首页 | 会员中心 | 我要投稿 站长网 (https://www.jiakaowang.com/)- 应用程序、AI行业应用、CDN、低代码、区块链!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

SQL Server存储过程+触发器:零基础打造高可用数据审计系统

发布时间:2026-10-27 08:02:11 所属栏目:MsSql教程 来源:DaWei
导读:  去年8月,选题会上我拿SQL Server存储过程+触发器那个审计系统方案刚开口,总编就把笔帽拧下来又咔嗒扣回去——那支中性笔一直立在笔记本右上角,没动过。我数过,三十七次选题会,它就立了三十七次,笔尖朝北,墨囊半空。  

  去年8月,选题会上我拿SQL Server存储过程+触发器那个审计系统方案刚开口,总编就把笔帽拧下来又咔嗒扣回去——那支中性笔一直立在笔记本右上角,没动过。我数过,三十七次选题会,它就立了三十七次,笔尖朝北,墨囊半空。


  我原以为是讲清“零基础”怎么起手:建个audit_log表,写个通用@table_name/@action/@user的SP,再套三层嵌套TRY/CATCH兜住SET XACT_ABORT ON失效的坑……结果总编翻了个白眼,手指敲两下桌面:“高可用?你这触发器一改,主库redo日志直接涨20%——谁扛?”


  我说我测过,开READ COMMITTED SNAPSHOT,加sp_set_session_context传session_id,用EXEC sys.sp_executesql动态拼schema_qualified名称,连带delete/update时old值查sys.dm_exec_requests取login_time做伪事务ID——这个我敢打包票,跑通了。但他说“零基础”三个字太飘,不如改成“给DBA留后门”。我没接话,因为隔壁桌小编正把冰美式打翻在键盘上,褐色水渍漫过F12键,她抽了三张纸巾按着,没抬头。


  优胜劣汰——不是指技术选型淘汰人,是指这个方案自己会吃掉烂代码。比如有人在SP里硬写INSERT INTO audit_log VALUES (GETDATE(), @@SPID, …),忘了ISNULL(@@PROCID, 0),结果审计表里一堆NULL proc_id;再比如trigger里调用xp_cmdshell导出日志,一上线就被安全策略秒禁;还有人把inserted/deleted当成永久表用,没加IF EXISTS(SELECT FROM inserted)就直接JOIN——这些,系统自己就会卡死、报错、吞数据、漏字段。它不教育你,它只等你犯错,然后沉默地崩给你看。


  外卖凉在会议桌左下角第三格,铝箔盒盖掀了一半,红油浮在牛肉粒上,像一层薄漆。没人动。总编说“高可用”得支持集群failover,我说触发器在AlwaysOn可用性组里默认disabled,得手动启,而且要配DTC或用service broker中转变更事件——可这个我说不准,我们没上过真正跨数据中心的AG,只在测试环境模拟过两次故障转移,一次是日志传送中断,另一次是仲裁节点宕机,第二十五分钟恢复时,审计表缺了十八条update记录,但没人去查是不是因为trigger里的WAITFOR DELAY '00:00:01'被超时截断了……这种事,文档不会写,微软也没明说,全靠撞。


文章配图,仅供参考

  前天作者群里有人发截图:他删了一行配置,触发器顺手记了log,结果审计表自己锁死阻塞住了主业务表——因为audit_log建了带INCLUDE的非聚集索引,而他insert时没显式指定列顺序,导致执行计划用了KEY LOOKUP查基表,基表和audit_log循环等待。我回了句“索引字段顺序得跟insert语句严格对齐”,他回了个流泪猫猫头。其实我上周也干过同样的事,只是那天我手抖多写了句OPTION (RECOMPILE),侥幸躲过去了。


  还有一次,我在SSMS里右键→修改一个trigger,刚点保存,弹窗提示“无法保存更改,需要删除并重新创建”,我点了确定,结果触发器真没了,连带同名的SP也消失了——后来发现是SSMS自动生成脚本时误删了create proc那行,只留了alter trigger,而我复制时没看清,全粘过去执行了。这个锅,我不推给SSMS,我推给那个“零基础”的幻觉:好像只要语法不错,就能活着落地。


  财务部上周提需求要补三个月前的订单变更溯源,我们翻审计日志,发现某天凌晨两点十七分的数据全部为空。查作业历史,发现backup job执行时占满了tempdb,触发器里的临时表#changed_rows分配失败,但没抛异常,只默默return了。监控邮件没发,因为告警规则写了“audit table rowcount drop >50%”,而那天drop的是99.8%,它没触发阈值——阈值设得太整,像某种仪式感。现在想想,真该设成49.7%,或者干脆用stddev做动态基线。


  小编把湿纸巾扔进垃圾桶时碰倒了笔筒,那支中性笔终于倒了,滚到地毯缝里去了。总编手机响了一声,来电显示是“人力-绩效面谈”。我没抬头。这时候说啥都像辩解。


  KPI填表又到了。上季度我负责的自动化脚本覆盖率算的是“含触发器逻辑路径的测试case数量 / 所有DDL+DML操作类型数”,领导看了说“太虚”,让我拆成“是否覆盖nested trigger call stack深度=3”“是否验证CONTEXT_INFO内存泄露边界”——这种指标写出来像行为艺术。但我还是填了。因为不填,年终奖基数少百分之七,而百分之七,刚好够我续三个月的Azure SQL高级版试用期,好接着测那个带memory-optimized table的审计增强版。


  其实我试过把所有审计逻辑搬到应用层,用EF Core的ChangeTracker做统一拦截,写完才发现有个老接口直连数据库跑BulkCopy,绕过了ORM。又试过用CDC,结果运维说开启CDC要停库三十分钟,生产不敢批。最后回到触发器——它丑,它重,它难调试,但它只要CREATE好了,就不依赖任何中间件、网络链路、连接池配置。它趴在表底下,呼吸同步,心跳同频,你删一行,它立刻记一笔,哪怕服务器只剩最后一瓦电,只要SQL Server引擎还挂着,它就还没死透。


  下次选题会我打算带根新笔,但不拧开。就让它躺着。反正方案大概率过不了,总编刚升总监,最近特别爱说“架构前瞻性”。而我,昨天重装了SSMS,顺手删掉了旧版本里所有带“audit_backup_v2_bak”命名的文件夹——一共三百七十二稿。有些连注释都没写完,有些连GO都少打了一个。


  这篇可能活不过三小时。

(编辑:站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!