|
此SQL数据库修复案例是北方某集团UFIDA U9系统,操作系统Win2008R2,数据库采用Microsoft SQL Server 2008 R2,IBM 3650M3加IBM存储,UFIDA U9系统与虚拟化平台共用同一台存储。
数据库损坏之前的几个月发生过几次断电扩展虚拟化平台,在11月UFIDA U9报出IO错误,用户尝试重建索引及修复数据库中彻底导致瘫痪,存储进行了磁盘扫描及修复,数据库损坏后又分别在不同时间段在同一存储内进行了备份与数据库拷贝工作。
该数据库检测发现损坏相当严重,系统表损坏、页撕裂、索引断裂、一致性错误等分配错误和一致性错误。通过用户操作想从存储中收集残缺页碎片变的十分渺茫,任务变的十分困难,原库无修复的可能性,逻辑结构严重损坏了,唯一幸运的是UFIDA U9系统报出IO错误错误时,多个部门模块还可以继续使用,用户自行修复导致的整个数据库瘫痪,怀疑数据表内的数据是早起的发生了问题,修复的动力大大增加。
本次UFIDA U9系统数据库修复案例通过SQL命令+底层修改方式,成功恢复了所有数据。表数据、存储过程、函数、视图等全部正常恢复。UFIDA U9系统直接启动运行。
将损坏的数据库挂载检查,查询数据库发现正常的数据表数据迁移访问都不行,错误如下:
在尝试加载程序集 ID 65536 时 Microsoft .NET Framework 出错。服务器可能资源不足,或者不信任该程序集,因为它的 PERMISSION_SET 设置为 EXTERNAL_ACCESS 或 UNSAFE。请重新运行查询,或检查有关的文档了解如何解决程序集信任问题。有关此错误的详细信息:
System.IO.FileLoadException: 未能加载文件或程序集“ufida.u9.sql.clrlib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null”或它的某一个依赖项。发生与安全有关的错误。 (异常来自 HRESULT:0x8013150A)
System.IO.FileLoadException:
在 System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
在 System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
在 System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
在 System.Reflection.Assembly.Load(String assemblyString)
消息 10314,级别 16,状态 11,第 1 行
这说明数据库存在EXTERNAL_ACCESS 和UNSAFE的程序集,要解决此问题,要想完成数据迁移,原库与目标库库所有者必须设为SA或Administrator,然后启用SQL CLR,否则SQL CLR的安全性会认为该程序集不可靠,从而无法进行数据表任何操作。
- 数据库的OWNER设置成SA语句.
- exec sp_changedbowner 'sa'
复制代码
- --如果没有启用CLR,开启
- EXEC sp_configure 'clr enabled',1
- RECONFIGURE WITH OVERRIDE;
复制代码
- --查看程序集,是存在的.
- SELECT * FROM sys.assemblies;
- SELECT * FROM sys.assembly_files;
- --还原之后的数据库TRUSTWORTHY 都是OFF的,需要重新设置
- ALTER DATABASE B SET TRUSTWORTHY ON;
复制代码
再次进行数据库检查:
消息 8905,级别 16,状态 1,第 1 行
数据库 ID 6 中的区 (1:2360) 标记为已在 GAM 中分配,但没有任何 SGAM 或 IAM 分配过该区。
消息 8906,级别 16,状态 1,第 1 行
数据库 ID 6 中的页 (1:14873122) 在 SGAM (1:14825729) 和 PFS (1:14865744) 中进行了分配,但未在任何 IAM 中分配。PFS 标志 'IAM_PG MIXED_EXT ALLOCATED 0_PCT_FULL'。
消息 8939,级别 16,状态 98,第 1 行
表错误: 对象 ID 0,索引 ID -1,分区 ID 0,分配单元 ID 5787249855381372928 (类型为 Unknown),页 (32768:524353)。测试(IS_OFF (BUF_IOERR, pBUF->bstat))失败。值为 12716041 和 -12。
消息 2575,级别 16,状态 1,第 1 行
索引分配映射(IAM)页 (0:0) (位于对象 ID 7,索引 ID 1,分区 ID 458752,分配单元 ID 458752 (类型为 In-row data))的下一个指针指向了 IAM 页 (1:21),但扫描过程中检测不到它。
消息 2576,级别 16,状态 1,第 1 行
索引分配映射(IAM)页 (1:521140) (位于对象 ID 7,索引 ID 1,分区 ID 458752,分配单元 ID 458752 (类型为 In-row data))的上一个指针指向了 IAM 页 (1:21),但扫描过程中检测不到它。
消息 8928,级别 16,状态 2,第 1 行
对象 ID 7422475,索引 ID 1,分区 ID 72057615584722944,分配单元 ID 72057623984144384 (类型为 In-row data): 无法处理页 (1:14877728)。有关详细信息,请参阅其他错误消息。
此处省略N万字...
---------------------------------------- 使用分界线 就是这么任性 ----------------------------------------
本次案例对于数据库表结构、视图、存储过程、用户定义函数等可以通过基础库使用SQL命令创建脚本,表内数据通过SQL命令配合底层修改方式提取,无法使用第三方数据库修复软件工具,以下会描述这个这个问题:
InToHard.com 田工先提取一个表数据导库测试发现数据无法入库,检查出是很多数据表带有键值、约束以及结构依赖;
这岂不是麻烦啦,第三方工具在导库上会怎么样呢?测试发现第三方工具带有EXTERNAL_ACCESS 和UNSAFE正常表都无法完成,带有约束的只能建出表,SQLsysTools打开100G数据库直接停止响应。
把约束以及结构依赖关闭,导库完成后加回去
数据库表数据量5000多个,要想在最短的时间完成数据库的修复工作,那么就要修复与回导同时开展来节省时间,数据库表修复过程中,有极个别表出现了少量丢失。
查询发现表内数据量庞大,上千万....
把损坏表数据提取后导回需要非常长的时间,用导入导出向导,一个表有的几个小时,时间等不及,采用了一个基础库,依据数据库情况使用了SQL游标导入,遇到导库的时候可以修改一下参数直接使用;
- ----table游标 一共5000个表 500个表 打开窗口执行以下
- DECLARE unuserNos_cursor CURSOR
- FOR
- SELECT A.name
- FROM ( SELECT name ,
- ROW_NUMBER() OVER ( ORDER BY ID ) AS number
- FROM sysobjects
- WHERE xtype = 'U'
- ---AND name NOT LIKE 'PM_%'
- and name not in ('sm_soline','PM_PMStatistics','PM_PMStatistics_Trl')
- ) AS A
- WHERE A.number > 0
- AND A.number <1000
-
- DECLARE @TableName NVARCHAR(200)
- DECLARE @sql NVARCHAR(MAX)
- OPEN unuserNos_cursor
- FETCH NEXT FROM unuserNos_cursor INTO @TableName
- WHILE @@FETCH_STATUS = 0
- begin
- begin try
-
- select @sql=A.SQL from inserSQL A where A.name=@TableName
- -- select @sql
- EXEC (@sql)
- print @TableName
- end try
- Begin Catch
- insert into error_table
- select @TableName,cast(error_number() as int),error_message(),cast(error_state() as int),
- CAST(error_severity() as nvarchar)
-
- End Catch
- FETCH NEXT FROM unuserNos_cursor INTO @TableName
- end
- CLOSE unuserNos_cursor
- DEALLOCATE unuserNos_cursor
-
- --DELETE FROM error_table
- --create table error_table(name nvarchar(200),error_number int,error_message nvarchar(2000),
- --error_state int,error_severity nvarchar(200))
- select * from error_table
复制代码
基础库的改动与现有数据引入后发现数据不是很精确,问题排查起来比较麻烦。
InToHard.com 田工通过SQL聚焦方式查询分析后,采用BCP命令方式多文件并行导入脚本大批量回导数据恢复成功。
通过损坏时间,查询损坏表最后一行,判断数据修复情况;
(INTOHARD.COM 田工) |
|