SQL 存储过程调试与日志记录方法

1次阅读

sql server存储过程日志需写入数据库表而非print;建日志表记录存储过程名、消息和时间;避免循环内高频插入;print仅限调试且上线前须移除。

SQL 存储过程调试与日志记录方法

SQL Server 存储过程中怎么加日志?

直接用 PRINT 不行——它只在 SSMS 的“消息”窗口输出,应用层完全收不到,也不落盘。真要留痕,得写进表里。

  • 建一张轻量日志表:CREATE table dbo.sp_log (id INT IDENTITY(1,1), proc_name NvarCHAR(128), msg NVARCHAR(500), log_time DATETIME2 default GETDATE());
  • 在关键节点插入记录:INSERT INTO dbo.sp_log (proc_name, msg) VALUES (OBJECT_NAME(@@PROCID), '开始处理订单ID: ' + CAST(@order_id AS VARCHAR));
  • 避免高频写入拖慢主流程:不要在循环体内每轮都插日志;用 @@ROWCOUNT 或条件判断控制触发时机
  • PRINT 仅用于本地调试时快速验证逻辑分支,上线前必须删掉或注释

mysql 存储过程没法用 select 查看变量值?

MySQL 不支持像 SQL Server 那样用 SELECT @var 直接查看变量(除非你把它当结果集返回),而且 SELECT 会干扰调用方对结果集的解析。

  • 临时调试用:SELECT CONCAT('DEBUG: ', @var) AS debug_output;,但必须确保这是存储过程的**最后一个** SELECT,否则业务代码可能误读
  • 更稳妥的方式是写入临时表:CREATE TEMPORARY TABLE if NOT EXISTS debug_tmp (ts DATETIME, val TEXT); INSERT INTO debug_tmp VALUES (NOW(), @var);
  • 注意权限:临时表只在当前会话可见,断开连接即消失;生产环境禁用 SELECT 调试,改用日志表
  • 变量名区分大小写(取决于系统变量 lower_case_table_names 设置),别写成 @Var@var 混用

postgresql 存储过程报错 “Error: cannot execute INSERT in a read-only transaction”?

这是典型日志写入失败场景:你用了 SECURITY DEFINER 或函数被定义为 STABLE/IMMUTABLE,导致事务上下文只读。

  • 检查函数定义:CREATE OR REPLACE function ... AS $$ ... $$ LANGUAGE plpgsql SECURITY DEFINER; —— 如果没显式声明 volatile,默认可能是 STABLE,禁止写操作
  • 必须加上 VOLATILE:例如 CREATE OR REPLACE FUNCTION log_msg(msg TEXT) RETURNS void VOLATILE AS $$ ... $$
  • 日志表需提前授权:GRANT INSERT ON TABLE public.proc_log TO your_function_owner;
  • 别在 EXCEPTION 块里再抛新异常后还试图写日志——如果事务已回滚,INSERT 会直接失败

所有数据库通用的日志字段设计要点

日志不是记流水账,字段设计不当会导致查不到、看不懂、查太慢。

  • 必加字段:proc_name(用 OBJECT_NAME(@@PROCID) / current_schema() || '.' || current_function() 等动态获取)、log_time(用 GETDATE() / NOW() / CURRENT_TIMESTAMP)、session_id(SQL Server 的 @@SPID,PG 的 pg_backend_pid()
  • 避免存长文本到主键或索引字段;把完整错误存在 TEXT 类型列,用 error_code 单独提出来便于 WHERE 查询
  • 定期清理:用分区表或定时任务删 7 天前数据,别让日志表撑爆磁盘
  • 别把敏感参数(如密码、身份证号)原样记进日志——脱敏后再写,比如 REPLACE(@card_no, SUBSTRING(@card_no, 5, 8), '********')

日志表结构和写入时机比日志内容本身更容易出问题。尤其跨数据库迁移时,VOLATILESECURITY DEFINER、事务隔离级别这些隐性约束,不报错但就是不写日志。

text=ZqhQzanResources