我有一个损坏的表,1 个大约 160 万行的可疑页面变成了一个 290 万行的表。我想尝试这个:
ALTER DATABASE [CorruptDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
DBCC CHECKDB (CorruptDB, REPAIR_ALLOW_DATA_LOSS) WITH TABLOCK;
..但我想知道如何确定数据丢失前后的行数。如果我做:
UPDATE STATISTICS [corrupt_table] WITH FULLSCAN;
它失败了,因为当然有一个撕裂的页面中途向下。这同样适用于:
SELECT COUNT(*) FROM [corrupt_table];
我想我的问题是,非全扫描UPDATE STATISTICS
肯定会正确更新行数吗?
我知道这只是一页破损的页面,应该相当于此表中的大约 100 行,我只是想确定一下。
注意:这不是在生产系统上,它只是在我的笔记本电脑 (2012 Std x64) 上本地,实际问题已经解决(通过恢复)——我已经拿了一份数据库来玩。
应对腐败:
第一:你有没有机会在页面变坏之前有一个好的备份?如果是这样,那么您可以进行页面恢复而不是修复数据丢失。这肯定是您最好的选择。请记住,在大多数情况下,导致磁盘错误的损坏不会影响您的事务日志。因此,只要您的完整备份有一个好的页面,您就可以从完整备份中恢复坏页,然后从那时起应用所有事务日志(当然只恢复那一页)。当然,这只有在您完全康复的情况下才有效。 https://msdn.microsoft.com/en-us/ms175168.aspx?f=255&MSPPError=-2147217396
你也可以看看这里做了什么:http: //stevestedman.com/2015/04/a-weekend-full-of-database-corruption/
如果您查看 Brent Ozar 的回答,他使用非聚簇索引与聚簇索引的比较(所有损坏都在聚簇索引上,就像我猜您的索引是单页一样)来查找实际损坏。然后他还能够通过相同的方法(聚集索引与非聚集索引)恢复丢失的信息。
实际问题
您可以尝试使用 sys.partitions 进行计数。根据我的经验,它们几乎总是正确的。不能保证你的腐败,但它应该是好的,特别是如果你比较多个索引。
如果损坏发生在单个页面中(或者如果至少一个非聚集索引中没有损坏),那么您将至少有一个没有问题的索引,并且 sys.partitions 应该是正确的。当然,您也可以这样做以强制您的计数查看未损坏的索引。
您无法准确确定将丢失的内容。这取决于页面撕裂的严重程度。
你能做什么?
通常的建议是从有问题的表中复制所有数据(根据您的数字相当大的副本)并将数据存储在数据库之外的其他地方。使用 BCP、SSIS 或脚本向导(但不是 BACKUP 和 RESTORE)将数据获取到磁盘上的文件中。然后:
然后将磁盘上的数据文件加载到一个新的临时数据库中(例如 RepairRecovery)。完成后,您可以比较原始的、现在“已修复”的数据库与您能够从磁盘文件中恢复的数据之间的数据。(有一些工具可以帮助您比较数据,或者您可以只查找丢失的 ID 或类似的东西。)