4. 源与目标环境盘点

迁移升级项目真正开始动手之前,最容易被低估、却最决定成败的一步,是源环境与目标环境的全面盘点。很多迁移事故并非发生在数据搬运阶段,而是发生在“我们以为已经知道源库有什么”的阶段:某个被遗忘的链接服务器、一个依赖 CLR 程序集的存储过程、一个每天凌晨跑批的 SQL Agent 作业、一个用 SQL 登录而非 Windows 登录的应用账号,都可能在切换后集中爆发。盘点的目标不是罗列清单,而是建立一张可迁移性地图:哪些对象能直接搬、哪些需要改写、哪些依赖外部资源、哪些必须重新配置。

盘点对象的分层结构

建议按“实例层 → 数据库层 → 对象层 → 依赖层 → 外围层 → 安全层”六个层次推进,每一层都有明确的采集手段和判断标准。

实例层关注版本、版本号、补丁级别、排序规则、实例级配置。核心命令是 SELECT @@VERSION 与 SERVERPROPERTY,重点看 ProductVersion、ProductLevel、Edition、Collation、IsClustered、IsHadrEnabled。排序规则尤其关键:如果源实例是 Chinese_PRC_CI_AS,目标实例却是 SQL_Latin1_General_CP1_CI_AS,跨实例的临时表连接、字符串比较都可能出现不一致。实例级配置还包括 max server memory、max degree of parallelism、cost threshold for parallelism、backup compression default 等,这些参数在目标环境需要重新评估,而不是照搬。

数据库层要采集数据库清单、恢复模式、兼容级别、大小、文件布局、是否启用 CDC/变更跟踪/Service Broker、是否参与镜像或可用性组。兼容级别是升级的核心变量:从 SQL Server 2016 的 130 升到 2022 的 160,兼容级别可以暂时保留,但必须评估 sys.dm_db_persisted_sku_features 和已弃用功能。数据库大小与文件布局决定迁移窗口:一个 2TB 的库用备份还原可能需要数小时,而用日志传送或 AlwaysOn 做预同步则可以把停机窗口压缩到分钟级。

对象层是盘点中最细碎的部分。表、视图、存储过程、函数、触发器、索引、约束、同义词、序列、用户定义类型、CLR 对象、全文索引、分区方案与分区函数,都要逐一登记。对象数量可以用系统视图快速统计:

SELECT type_desc, COUNT(*) AS cnt
FROM sys.objects
WHERE is_ms_shipped = 0
GROUP BY type_desc
ORDER BY cnt DESC;

但数量只是起点,真正需要标记的是风险对象:使用了已弃用语法(如 SET ROWCOUNT、旧式 *= 外连接)、依赖 xp_cmdshell、依赖特定排序规则、使用了 TEXT/NTEXT/IMAGE 旧数据类型、包含跨库三部分命名引用的对象。这些对象在目标环境往往需要改写或额外授权。

依赖关系:盘点的真正难点

对象之间的依赖关系决定了迁移顺序和影响范围。SQL Server 提供 sys.sql_expression_dependencies 来追踪对象级依赖,但它对动态 SQL、跨库引用和 CLR 的覆盖有限。实际盘点中,建议把依赖分为四类:

  • 库内依赖:视图依赖表、存储过程依赖视图、函数被计算列引用。这类依赖可以通过脚本按依赖顺序生成,通常可控。
  • 跨库依赖:存储过程中出现 OtherDB.dbo.Table 三部分命名。迁移时如果目标实例的库名或实例名变化,必须改写或建立同义词。
  • 跨实例依赖:通过链接服务器访问远程数据。这类依赖在目标环境需要重建链接服务器、重新配置安全映射,并验证网络连通性。
  • 外部依赖:CLR 程序集、外部表、PolyBase、机器学习服务、文件表。这些依赖操作系统和实例级功能,迁移前必须确认目标环境已启用对应特性。

一个实用的做法是先用 sys.sql_modules 做文本扫描,找出所有包含三部分命名和 OPENQUERY、OPENDATASOURCE 的对象,再结合 sys.sql_expression_dependencies 做交叉验证。对于动态 SQL 拼接的依赖,文本扫描是唯一可靠手段。

外围应用、作业与链接服务器

外围应用是“数据库之外但属于同一业务系统”的部分,包括 SSIS 包、SSRS 报表、SSAS 多维/表格模型、Power BI 数据集、外部应用程序连接串、ODBC/JDBC 驱动版本。盘点时要记录每个外围应用连接的数据库、使用的账号、连接方式(Windows 集成或 SQL 登录)、是否使用加密连接。SSIS 包尤其要注意:包中可能硬编码了源服务器名,迁移后需要重新配置连接管理器。

SQL Agent 作业是另一个高频遗漏点。作业不仅包含 T-SQL 步骤,还可能包含 SSIS 步骤、PowerShell 步骤、操作系统命令步骤、复制步骤。盘点时要采集作业名称、步骤类型、调度计划、目标数据库、运行账号、是否启用、历史执行结果。可以用以下查询快速导出:

SELECT j.name AS job_name, j.enabled, s.step_id,
       s.subsystem, s.database_name, s.command
FROM msdb.dbo.sysjobs j
JOIN msdb.dbo.sysjobsteps s ON j.job_id = s.job_id
ORDER BY j.name, s.step_id;

链接服务器盘点要记录名称、提供程序、数据源、产品名、访问接口、安全映射方式(sp_addlinkedsrvlogin 的 useself 设置)。如果源环境使用 useself = true 依赖 Kerberos 委派,目标环境必须确认 SPN 和委派配置是否同步迁移。

安全主体:最容易被“看起来没问题”掩盖的部分

安全主体包括登录名、数据库用户、角色、架构、权限、证书、非对称密钥、凭据、审核。迁移时常见的问题是:登录名在目标实例不存在,导致数据库用户成为“孤立用户”;或者登录名存在但 SID 不同,权限映射错乱。盘点时要采集登录名类型(SQL 登录/Windows 登录/证书/非对称密钥)、SID、默认数据库、是否启用、服务器角色成员资格。数据库用户要采集对应的登录名、默认架构、数据库角色成员资格、显式权限。

对于 SQL 登录,密码无法直接导出,迁移时需要重新设置或使用 sp_help_revlogin 类脚本保留 SID 和密码哈希。对于 Windows 登录,要确认目标域或信任关系是否可达。对于包含 EXECUTE AS 或签名模块的对象,证书和非对称密钥必须一并迁移,否则模块签名失效。

盘点成果建议落成一份“迁移对象登记表”,至少包含:对象类型、对象名、所属数据库、风险等级、迁移方式(直接迁移/改写/重建/废弃)、依赖对象、负责人、验证方法。风险等级可按“高(需改写或外部依赖)/中(需重新配置)/低(可直接迁移)”三档划分。

源与目标环境盘点的关系视图

下面的 SVG 用一张关系图把六层盘点对象、它们之间的依赖方向以及迁移时的处理动作组织在一起,帮助在动手前建立整体判断。

源环境与目标环境盘点关系图 六层对象 · 依赖方向 · 迁移处理动作 源环境(Source) 实例层 版本 / 补丁 / 排序规则 / 配置 数据库层 恢复模式 / 兼容级别 / 大小 对象层 表 / 过程 / 函数 / 索引 / CLR 依赖层 库内 / 跨库 / 跨实例 / 外部 外围层 SSIS / SSRS / 应用 / 作业 安全层 登录 / 用户 / 角色 / 证书 盘点与处理动作 采集版本与配置基线 对比目标实例差异 评估兼容级别与功能 确定迁移窗口与方式 对象分类与风险标记 直接迁移 / 改写 / 废弃 依赖排序与改写清单 三部分命名 / 链接服务器 外围应用连接串核对 作业步骤与调度重建 登录 SID 与权限映射 证书 / 凭据 / 审核迁移 目标环境(Target) 实例就绪 版本 / 补丁 / 排序规则一致 数据库就绪 兼容级别 / 文件布局确认 对象就绪 脚本部署 / 编译通过 依赖就绪 链接服务器 / 同义词重建 外围就绪 应用连通 / 作业启用 安全就绪 登录映射 / 权限验证 高风险依赖 跨库三部分命名 · 链接服务器 · CLR · 动态 SQL

这张图强调一个判断:依赖层是源与目标之间真正的“桥”,它把对象层、外围层和安全层串在一起。盘点时如果只登记对象清单而不追踪依赖,迁移脚本很可能因为执行顺序错误或外部引用缺失而失败。实际项目中,建议把依赖清单与对象登记表合并维护,每标记一个高风险依赖,就同步确定改写方案、验证方法和回退策略。

最后需要提醒的是,盘点不是一次性动作。源环境在迁移窗口前仍可能发生变化:新增作业、修改存储过程、调整权限。因此在正式切换前 24 小时内,应再做一次增量比对,重点检查对象数量、作业调度、登录名和链接服务器的变化。只有把“静态清单”变成“可复核的基线”,盘点才真正为迁移升级提供了可靠依据。