必须将日志写入数据库表而非PRINT,因PRINT不落盘、应用层不可见且上线后无效;建轻量表如dbo.sp_log,字段含BIGINT IDENTITY id、OBJECT_NAME(@@PROCID)取名、DATETIME2(3)时间,禁用不可靠字段如ClientIP,避免循环内高频插入,日志写入须剥离主事务以防锁争用与性能拖累。

不能靠 PRINT 记每一步——它不落盘、应用层收不到、上线后等于没记。
SQL Server 存储过程里怎么写入可查的日志表
必须把日志写进数据库表,且字段设计要克制。建一张轻量表就行:
CREATE TABLE dbo.sp_log ( id BIGINT IDENTITY(1,1), proc_name NVARCHAR(128), msg NVARCHAR(500), log_time DATETIME2(3) DEFAULT GETDATE() );
-
id用BIGINT IDENTITY,别用UNIQUEIDENTIFIER,后者插入性能差三倍 -
proc_name用OBJECT_NAME(@@PROCID)动态取,别硬编码字符串 -
log_time必须是DATETIME2(3),DATETIME精度低、时区支持弱 - 别加
HostName、ClientIP这类字段——连接池下全是127.0.0.1或应用服务器名,不可信
在存储过程中插入日志的正确时机和写法
关键不是“能不能插”,而是“插在哪”“插多少”。高频写入会拖慢主流程,尤其在循环里每轮都 INSERT 是典型反模式。
- 只在分支入口、关键计算前、事务提交/回滚前这类节点写日志
- 用
@@ROWCOUNT或条件判断控制触发,比如只在影响行数 > 0 时才记录 - 避免在
TRY...CATCH的CATCH块里再写日志后抛异常——事务若已回滚,INSERT会直接失败 - 示例写法:
INSERT INTO dbo.sp_log (proc_name, msg) VALUES (OBJECT_NAME(@@PROCID), '订单ID: ' + CAST(@order_id AS VARCHAR(20)) + ' 开始校验');
为什么不能在主事务里同步写日志表
日志写入本身也是 DML 操作,会延长事务时间、加剧锁争用。高并发场景下,一次 INSERT 日志可能让响应从 20ms 拉到 300ms。
- 日志表必须独立 schema(如
audit.LogEntry),禁用触发器、外键、冗余索引 - 主逻辑中用
INSERT INTO audit.LogEntry WITH (TABLOCK)减少锁开销,但注意与READ_COMMITTED_SNAPSHOT冲突 - 更稳妥的做法是:把日志写入剥离出主事务,用显式
COMMIT单独提交,或走异步机制(如 Service Broker) -
PRINT只能用于本地调试,上线前必须删掉或注释——它连事务都不属于,纯属 SSMS 消息窗口玩具
真正难的不是“怎么写日志”,而是判断哪一步值得记、哪一步写了反而干扰排查。比如参数值要不要记?完整 SQL 要不要存?这些细节一旦放开,日志表很快变成性能黑洞和查询负担。

















