直接比对结果集不可靠,因存储过程与直接执行SQL的环境(参数嗅探、会话设置、兼容性级别)天然不同;必须控制变量,通过统一SET选项、替换字面量参数、对比执行计划与数据特征来验证逻辑等价性。

直接比对结果集本身不可靠,因为存储过程执行环境(参数嗅探、会话设置、兼容性级别)和 SQL 直接执行天然不同;必须控制变量,把“过程逻辑是否等价”转化为可重复验证的步骤。
用相同参数+相同会话上下文重放查询
存储过程不是黑盒,它的核心 SQL 可以被提取出来单独运行。关键在于让两者运行在完全一致的会话环境中:
- 在 SSMS 或其他客户端中,先执行
SET NOCOUNT ON; SET ANSI_NULLS ON; SET QUOTED_IDENTIFIER ON;,再执行存储过程——这些是创建过程时默认启用的会话选项,漏掉会导致结果集结构或 NULL 处理行为不一致 - 把过程体里实际执行的
SELECT语句复制出来,**手动替换所有参数为字面量值**(如把@date换成'20230101'),并在同一会话中执行 - 对比两者的输出:行数、列名、数据类型(特别是
datetimevsdatetime2)、NULL/空字符串处理、排序稳定性(过程里没ORDER BY时,结果顺序不保证)
检查执行计划是否实质变化
结果一样但性能崩了,往往意味着执行路径变了。重点看是否触发了参数嗅探劣化或索引跳过:
- 对存储过程加
WITH RECOMPILE执行一次(EXEC proc_name @p = '20230101' WITH RECOMPILE),再捕获“实际执行计划” - 对等价的独立
SELECT也开“包含实际执行计划”,对比两个计划里的Index Seek/Scan节点、预估行数、警告(如“Missing Index”或“Convert Issue”) - 特别注意升级后是否出现
CONVERT_IMPLICIT:比如旧版把VARCHAR参数自动转成NVARCHAR不报错,新版可能因排序规则差异导致索引失效
绕过缓存强制测试真实逻辑
升级前后如果只改了兼容性级别(如从 130 升到 150),SQL Server 会复用旧计划缓存,掩盖真实行为变化:
- 执行
ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL = 150;后,立刻运行DBCC FREEPROCCACHE;清空计划缓存(生产环境慎用,仅验证阶段) - 或者更安全的方式:在过程定义里加
OPTION (RECOMPILE),确保每次调用都基于当前兼容级别重新生成计划 - 对 MySQL 8.0+ 升级,还要确认
sql_mode是否含ONLY_FULL_GROUP_BY;若过程里有GROUP BY,直接执行会报错,而旧版静默容忍——这是逻辑断裂点,不是结果不一致,而是根本跑不通
最容易被忽略的是变量作用域污染:比如过程里声明了 DECLARE @id INT,又查了 SELECT @id = id FROM t WHERE name = @name,但表里没匹配行,@id 就变成 NULL;而你手写的 SQL 用的是字面量 WHERE name = 'xxx',必然有结果。这种“查不到就留原值”的隐式逻辑,在升级后常因初始化严格化而暴露。

















