简介:这份文档面向需要将旧版数据库平滑升级的运维与开发人员,聚焦 SQL Server 2008 向 SQL Server 2012 迁移还原这一典型场景,属于数据库迁移方向的实操型参考资料。资源包内共 1 个 docx 文件,压缩包约 313KB,以图文步骤形式记录迁移全过程,便于按图索骥对照操作。内容围绕迁移前的准备工作展开,涵盖在 2012 中建立同名数据库、设置兼容级别为 2008 兼容、通过任务菜单执行复原数据库、指定备份文件与文件路径、选择覆盖现有数据库以及结尾日志备份的处理等关键环节,并配有对应界面截图辅助理解。目前已有 231 人学习下载,适合正在处理版本升级、需要一份可参照还原流程的数据库从业者,帮助梳理迁移思路、规避路径与兼容性设置上的常见疏漏。
1. SQL Server 2008 还原到 2012:一次版本跨越的真实翻车与修复
把 SQL Server 2008 的数据库还原到 SQL Server 2012,听起来只是点几下鼠标的事,但我见过太多人在这上面翻车。最常见的场景是:老服务器要下线,新服务器装好了 2012,备份文件也拷过去了,结果还原时报错“数据库版本不兼容”或者还原成功但应用连不上。这不是玄学,是兼容性级别、排序规则和备份链在作祟。这篇文章面向的是需要把 2008 的库迁到 2012 的 DBA 和后端开发,我会把还原的两种路径、参数怎么设、权限怎么给、以及我踩过的坑一条条讲清楚。你不需要有 2012 的专家经验,但得能连上实例、能执行 T-SQL。读完你能自己判断该用备份还原还是分离附加,知道还原后必须改哪几个设置,以及遇到“无法升级数据库”时先查什么。
2. 还原前的版本与兼容性判断:别急着点“还原”
2.1 先搞清楚 2008 和 2012 的版本号对应关系
SQL Server 2008 的内部版本号是 10.0,2008 R2 是 10.50,2012 是 11.0。备份文件里记录的是源实例的版本号,2012 的还原引擎只允许从更低版本还原,不允许从更高版本还原。也就是说,2008 的备份可以还原到 2012,但反过来不行。很多人以为“都是 SQL Server,应该通用”,结果拿 2012 的备份往 2008 上还原,直接报错。判断方法很简单,在源库执行:
-- 查看源实例版本和数据库兼容级别 SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion, SERVERPROPERTY('ProductLevel') AS ProductLevel, name AS DatabaseName, compatibility_level AS CompatLevel FROM sys.databases WHERE name = 'YourDBName';ProductVersion 返回 10.0.xxxx 或 10.50.xxxx 就是 2008/2008 R2,compatibility_level 一般是 100(2008)或 90(2005 兼容)。还原到 2012 后,兼容级别不会自动变成 110,需要手动改。这里有个常见误解:兼容级别只影响查询优化器行为,不影响还原本身。但如果你不改,应用可能因为执行计划变化而变慢,这是还原后性能问题的头号原因。
2.2 备份文件的选择:完整备份还是分离附加
从 2008 迁到 2012,常见做法有两种:备份还原和分离附加。备份还原更安全,因为源库可以继续在线,备份文件可以校验;分离附加更快,但要求源库脱机,而且 2008 的 MDF 文件直接附加到 2012 时,2012 会升级文件结构,一旦升级就再也回不去 2008 了。我一般会推荐备份还原,除非停机窗口极短且数据量巨大。备份时用:
BACKUP DATABASE [YourDBName] TO DISK = N'D:\Backup\YourDBName_Full.bak' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10;COMPRESSION 在 2008 标准版及以上支持,能显著减小备份文件;CHECKSUM 会校验页完整性,还原时如果页损坏会直接报错,避免还原出一个坏库。STATS = 10 每 10% 输出进度,方便判断是否卡住。备份完记得跑 RESTORE VERIFYONLY 验证:
RESTORE VERIFYONLY FROM DISK = N'D:\Backup\YourDBName_Full.bak' WITH CHECKSUM;如果验证报错,别急着拷到新服务器,先解决备份文件本身的问题。这一步能省掉很多来回折腾。
2.3 排序规则和实例级差异的预检
排序规则不一致是还原后应用报“无法解决 equal to 操作的排序规则冲突”的根因。2008 和 2012 的默认排序规则可能不同,尤其是中文环境常用 Chinese_PRC_CI_AS。在源库查:
SELECT DATABASEPROPERTYEX('YourDBName', 'Collation') AS DBCollation;在目标实例查:
SELECT SERVERPROPERTY('Collation') AS ServerCollation;如果两者不同,还原时不会报错,但跨库查询或临时表连接时会出问题。解决办法是在还原时用 WITH MOVE 指定数据文件位置,并在还原后不改排序规则,而是通过应用层或查询层显式 COLLATE。改数据库排序规则需要重建所有索引,代价极高,不建议在迁移时做。另一个预检项是实例功能差异:2008 用了哪些 2012 已弃用的功能,比如 BACKUP WITH PASSWORD 在 2012 被移除,如果备份时用了密码,2012 无法还原。检查备份语句里有没有 PASSWORD 关键字。
3. 用 T-SQL 完成还原:文件移动、恢复模式和权限
3.1 还原命令的完整写法与 WITH MOVE 参数
在 2012 实例上执行还原,不能直接点“还原数据库”就完事,因为 2008 的数据文件路径在 2012 上可能不存在。必须用 WITH MOVE 把逻辑文件名映射到新路径。先看备份文件里的逻辑文件名:
RESTORE FILELISTONLY FROM DISK = N'D:\Backup\YourDBName_Full.bak';返回的 LogicalName 列就是逻辑文件名,通常有数据文件和日志文件两个。然后写还原语句:
RESTORE DATABASE [YourDBName] FROM DISK = N'D:\Backup\YourDBName_Full.bak' WITH MOVE N'YourDBName' TO N'E:\Data\YourDBName.mdf', MOVE N'YourDBName_log' TO N'F:\Log\YourDBName_log.ldf', RECOVERY, STATS = 5, REPLACE;MOVE 后面的逻辑名必须和 FILELISTONLY 返回的完全一致,包括大小写。RECOVERY 表示还原后数据库可用,如果还有差异备份要还原,先用 NORECOVERY。REPLACE 表示如果目标库已存在就覆盖,生产环境慎用,测试环境常用。STATS = 5 每 5% 报进度。如果还原时报“操作系统错误 5(拒绝访问)”,是 SQL Server 服务账户对新路径没有写权限,去文件夹属性里给服务账户加完全控制。
3.2 还原后的兼容级别调整与统计信息更新
还原完成后,数据库兼容级别还是 100,需要手动升到 110:
ALTER DATABASE [YourDBName] SET COMPATIBILITY_LEVEL = 110;改完后执行计划会按 2012 的优化器生成。但别急着改,先跑一遍关键查询看性能,如果变慢再考虑回退。另一个必做项是更新统计信息:
USE [YourDBName]; GO EXEC sp_updatestats; GOsp_updatestats 会更新所有用户表的统计信息,但不会更新索引统计信息,大表可能耗时较长。如果时间紧,至少对核心业务表手动 UPDATE STATISTICS。还原后还要检查数据库所有者:
SELECT SUSER_SNAME(owner_sid) AS OwnerName FROM sys.databases WHERE name = 'YourDBName';如果所有者是源服务器的登录名,在 2012 上可能不存在,导致应用连不上。改成 sa 或有效登录名:
ALTER AUTHORIZATION ON DATABASE::[YourDBName] TO [sa];3.3 登录名与用户映射的修复
还原后数据库里的用户是源实例的登录名映射,但 2012 实例上可能没有对应的登录名,表现为“用户无法登录”。先查孤立用户:
USE [YourDBName]; GO EXEC sp_change_users_login 'Report';如果返回用户名但 LoginName 为 NULL,就是孤立用户。修复方法有两种:如果 2012 上已有同名登录名,用:
EXEC sp_change_users_login 'Update_One', 'UserName', 'LoginName';如果没有同名登录名,先创建登录名再映射:
CREATE LOGIN [LoginName] WITH PASSWORD = N'StrongPassword123!'; GO USE [YourDBName]; GO EXEC sp_change_users_login 'Update_One', 'UserName', 'LoginName';注意 sp_change_users_login 在后续版本被弃用,但 2012 上还能用。更现代的做法是 ALTER USER WITH LOGIN,但 2012 支持有限。权限方面,还原不会带源实例的服务器级权限,只带数据库级权限。如果应用需要跨库查询或执行 xp_cmdshell,得在 2012 上单独授权。
4. 避坑与排查:还原到 2012 最常见的 5 个翻车现场
4.1 报错“数据库版本 661 无法升级到 706”
现象:还原时直接失败,提示“无法升级数据库,因为数据库版本 661 高于当前实例支持的版本 706”。原因:661 是 2008 的数据库版本号,706 是 2012 的,但报错说 661 高于 706,说明你还原的方向反了——你拿 2012 的备份往 2008 上还原。解决:确认源和目标实例版本,2008 备份只能在 2012 或更高版本还原,不能反向。如果确实需要降级,只能用导出脚本或 SSIS 逐表迁移。
4.2 还原成功但应用报“排序规则冲突”
现象:应用查询报“无法解决 equal to 操作的排序规则冲突”,尤其是临时表和源表 JOIN 时。原因:tempdb 的排序规则和用户库不一致,临时表继承 tempdb 排序规则,和用户库列比较时冲突。解决:查 tempdb 排序规则:
SELECT DATABASEPROPERTYEX('tempdb', 'Collation');如果和用户库不同,在查询里显式 COLLATE:
SELECT * FROM YourTable t JOIN #TempTable tmp ON t.Name COLLATE Chinese_PRC_CI_AS = tmp.Name COLLATE Chinese_PRC_CI_AS;根治方法是重建 tempdb 排序规则,但需要重启实例,生产环境要排窗口。
4.3 还原后数据库变成“恢复挂起”或“可疑”
现象:还原后数据库状态显示“Recovery Pending”或“Suspect”。原因:日志文件缺失或损坏,或者还原时用了 NORECOVERY 但没继续还原日志。解决:先查状态:
SELECT name, state_desc FROM sys.databases WHERE name = 'YourDBName';如果是 Recovery Pending,尝试:
ALTER DATABASE [YourDBName] SET EMERGENCY; GO ALTER DATABASE [YourDBName] SET SINGLE_USER; GO DBCC CHECKDB (N'YourDBName', REPAIR_ALLOW_DATA_LOSS); GO ALTER DATABASE [YourDBName] SET MULTI_USER; GOREPAIR_ALLOW_DATA_LOSS 会丢数据,只在没有备份时用。如果有完整备份链,重新还原并确保日志文件路径正确。
4.4 备份文件拷到新服务器后无法读取
现象:RESTORE FILELISTONLY 报“无法打开备份设备,操作系统错误 5”。原因:SQL Server 服务账户对备份文件所在文件夹没有读权限,或者文件被压缩软件加密。解决:把备份文件放到 SQL Server 服务账户有权限的目录,比如默认备份目录。查服务账户:
SELECT servicename, service_account FROM sys.dm_server_services;给该账户加文件夹读权限。如果是网络路径,SQL Server 服务账户需要网络共享权限,建议先拷到本地再还原。
4.5 还原后自增列跳号或种子值异常
现象:应用插入数据时自增 ID 突然跳到 1000 以上。原因:还原时 SQL Server 会重新播种自增列,尤其是用了 DBCC CHECKIDENT 或批量插入后。解决:查当前种子值:
DBCC CHECKIDENT ('YourTable', NORESEED);如果种子值不对,用:
DBCC CHECKIDENT ('YourTable', RESEED, 0);RESEED 到 0 后下一条插入会从 1 开始,但如果有历史数据,要 RESEED 到最大 ID。更安全的方法是在还原前记录源库的种子值,还原后手动对齐。
5. 还原后的性能验证与回退预案
还原完成不代表迁移结束,我一般会做三件事:跑一遍核心查询对比执行时间、检查索引碎片、准备回退脚本。核心查询对比用 SET STATISTICS TIME 和 IO:
SET STATISTICS TIME ON; SET STATISTICS IO ON; GO -- 你的核心查询 SELECT * FROM YourBigTable WHERE CreateDate > '2024-01-01'; GO SET STATISTICS TIME OFF; SET STATISTICS IO OFF;对比 2008 和 2012 的逻辑读次数,如果 2012 明显偏高,可能是统计信息不准或兼容级别导致计划变化。索引碎片检查:
SELECT OBJECT_NAME(ips.object_id) AS TableName, i.name AS IndexName, ips.avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id WHERE ips.avg_fragmentation_in_percent > 30;碎片超过 30% 建议 REBUILD,10% 到 30% 用 REORGANIZE。回退预案很简单:保留 2008 的备份文件,如果 2012 上应用问题太多,直接切回 2008 实例。但注意,一旦 2012 上改过数据,回退会丢这部分数据,所以回退窗口内最好把应用设为只读或停写。我自己的习惯是:还原后先跑 24 小时只读流量,确认查询没问题再开写。这个习惯帮我避免过两次重大事故。希望帮到你。
本文还有配套的精品资源,点击获取