如何修复“可能的连锁链接问题”的损坏。

Tom*_*mas 5 sql-server-2008 sql-server corruption

我有一个包含 15 000 000 条记录的大表,突然 Select Top 停止工作。我使用 MS SQL 管理工作室。

这不起作用,查询返回 0 条记录:

SELECT TOP (10) 
       [Id]
      ,[Result]
      ,[DateStamp]
      ,[ConversionTime]
      ,[Converter]
      ,[SourceFileFormat]
      ,[DestinationFileFormat]
      ,[Ip]
      ,[Source]
      ,[Error]
      ,[UserId]
      ,[TokenId]
      ,[ConversionCost]
  FROM [ca-v2].[dbo].[Log]
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,如果我尝试选择一个 ID 字段,它会正常工作。

工作正常:

SELECT TOP (10) 
       [Id]        
  FROM [ca-v2].[dbo].[Log]
Run Code Online (Sandbox Code Playgroud)

此外,如果我在最后添加 order by 查询也开始工作:

SELECT TOP (10) 
       [Id]
      ,[Result]
      ,[DateStamp]
      ,[ConversionTime]
      ,[Converter]
      ,[SourceFileFormat]
      ,[DestinationFileFormat]
      ,[Ip]
      ,[Source]
      ,[Error]
      ,[UserId]
      ,[TokenId]
      ,[ConversionCost]
  FROM [ca-v2].[dbo].[Log]
  Order By [DateStamp]
Run Code Online (Sandbox Code Playgroud)

我跑到DBCC CHECKTABLE桌子上,收到以下错误:

错误:消息 8978,级别 16,状态 1,第 1 行

表错误:对象 ID 1029578706,索引 ID 1,分区 ID 72057594043367424,分配单元 ID 72057594045071360(类型行内数据)。页面 (1:5044) 缺少上一页 (1:5042) 的引用。可能的链条连接问题。

我该怎么办?

在@RDFozz 的帮助下,我能够使用 sql 修复损坏的索引

ALTER DATABASE "db" SET SINGLE_USER WITH ROLLBACK IMMEDIATE

go

DBCC CheckTable ("log", REPAIR_REBUILD) 

go

ALTER DATABASE "db" SET MULTI_USER WITH ROLLBACK IMMEDIATE
Run Code Online (Sandbox Code Playgroud)

这里有两件重要的事情:1) 必须将数据库设置为单用户模式。2) 如果数据库在生产中并且有其他连接,则 SET 用户命令必须使用 ROLLBACK IMMEDIATE 来删除当前连接。

RDF*_*ozz 11

当面临数据库损坏时,您需要确定问题的严重程度。你有一个损坏的表/索引,还是很多?您可能希望DBCC CHECKDB在数据库上运行。

根据您的发现,您有以下选择(按安全降序排列):

  1. 从备份恢复

    这通常是最简单、最安全的解决方案。但是,如果您不确定损坏是在多久之前出现的,这可能是不切实际的 - 您可能没有最近没有损坏的备份。而且,根据数据库的使用情况,就继续能够运行您的业务而言,丢弃一天的数据来修复损坏可能代价高昂。

    但是,如果损坏严重,这可能是您唯一可用的解决方案。即使您尝试了以下某些选项,您也可能需要回到这个选项。

    如果您有备份,请将它们放在手边,并且在解决问题之前不要循环使用(如果可能)。

  2. 使用DBCC CHECKTABLEDBCC CHECKDB与修复选项一起使用

    您的运行DBCC CHECKTABLE和/或DBCC CHECKDB可能已经表明您可以使用修复选项来尝试将事情恢复到正常状态。

    这些命令具有相同的修复选项:

    • REPAIR_FAST- 正如它所说,它尝试了一些简单的事情,并且比其他修复选项花费的时间更少。正如您可能猜到的,这也意味着它最不可能成功。

    • REPAIR_REBUILD- 这做了什么REPAIR_FAST,但也愿意尝试从头开始重建索引 - 问题出在非聚集索引中,这应该可以解决它。

    • REPAIR_ALLOW_DATA_LOSS- 正如所指出的,它将尝试将受影响的对象恢复到可用性,但可能必须消除部分行等;您可能会丢失一些数据。这是恢复备份通常是最佳解决方案的原因之一。

  3. Frankensteining 你的坏桌子(可以这么说)

    如果只有这张表受到影响,您可以尝试:

    • 找到表未损坏的备份(并以不同的名称建立备份);
    • 删除坏表;
    • 通过DBCC CHECKDB再次运行确认这没有将您的问题转移到其他地方;和
    • 从备份中复制表及其数据。


    或者,尝试保留尽可能多的新数据:

    • 准备好备份,如上
    • REPAIR_ALLOW_DATA_LOSS在桌子上使用。
    • 如果表现在正在工作,请在备份中找到不在修复表中的行,然后将它们复制进去。

正如CaM在评论中所指出的,您应该以此为动力,以确保您正在对数据库执行定期维护任务。

首先,如果您不是今天,请开始定期备份它。我管理的大多数数据库都有每周完整备份和每日差异备份,因此我们丢失的数据绝不会超过一天。

此外,您还应该DBCC CHECKDB定期运行,以便在损坏变得严重而无法修复之前发现损坏。这也是我每周尝试运行的内容。

  • @Tomas - 根据您的最新评论(日志中的数据并不重要),我会执行 `DBCC CHECKTABLE ('dbo.Log', REPAIR_REBUILD)`,并在需要时跟进 `REPAIR_ALLOW_DATA_LOSS`。 (2认同)