意外 DBA:不确定为什么我的日志链已损坏?

DB-*_*-GB 7 sql-server recovery restore

首先,感谢您查看这个 - 我们的生产环境中有一个大型数据库(1.26 TB),其中有几百个损坏的页面并且已经完成了几个月,所以所有的损坏都是一样的可用的备份。

上周晚些时候,我被拖入了这个阶段,因为似乎由于损坏,重新组织索引的预定作业已经失败了一段时间,我们现在处于最大和最常用表上的索引范围在 50% 和80% 的碎片严重降低了应用程序的性能。

我对如何解决这种情况提出了许多想法(相信我,我对替代方案持开放态度),从我读到的内容来看,我认为以下内容听起来是个好主意:

  1. 从生产 (SQL Server 2008R2) 中获取损坏数据库的压缩备份,复制到我们的(本地)开发服务器 (SQL Server 2016) 并运行修复(生产系统上没有足够的空间来拥有两个副本损坏的数据库同时附加)。
  2. 将此损坏备份的两个副本恢复到我们有足够空间的开发服务器上。
  3. 使用这些数据库之一的 allow_data_loss 选项在开发服务器上运行修复,重命名为“DbNameHereRepaired”(我使用 DBCC PAGE 查看的大多数损坏页面似乎都将其数据全部设置为 0x00)。
  4. 将其他副本重命名为 DbNameHereCorrupt,尝试使用以下代码运行页面级还原:

        alter database DbNameHereCorrupt set single_user with rollback immediate
    
        --set db to FULL recovery mode
        alter database DbNameHereCorrupt set recovery full
    
        --Declare paths for backups
        declare @fullBackupPath nvarchar(max) = N'D:\Restore\DbNameHereCorrupt-FullBackup.bck'
        declare @tranLogBackupPath nvarchar(max) = N'D:\Restore\DbNameHereCorrupt-LogBackup.bck'
    
        --Take full backup to begin new TLogChain
        backup database DbNameHereCorrupt to disk = @fullBackupPath with init, differential;
    
        --Immediately after whilst in single user mode, begin the t-log chain, this will also put the db in a restoring state
        backup log DbNameHereCorrupt to disk=@tranLogBackupPath with init, norecovery;
    
        --get corrupted pages
        declare @corruptedPages nvarchar(max) = 
        (
            select stuff
            (
                (
                    select ',' + cast(s.file_id as nvarchar(20)) + ':' + cast(s.page_id as nvarchar(20))
                    from msdb.dbo.suspect_pages s
    
                    where s.database_id = 20
    
                    for xml path('')
                ), 1 ,1, ''
            )
        )
    
        --push page-level restore
        restore database DbNameHereCorrupt
        page=@corruptedPages
        from disk=N'D:\Restore\DbNameHereRepaired.bak'
        with norecovery;
    
        -- restore log over db
        restore log DbNameHereCorrupt from disk=@tranLogBackupPath
        with norecovery;
    
        -- put db back into usable state
        restore database DbNameHereCorrupt
        with recovery
    
        --set db to SIMPLE recovery mode
        alter database DbNameHereCorrupt set recovery simple
    
        alter database DbNameHereCorrupt set multi_user
    
    Run Code Online (Sandbox Code Playgroud)

这似乎在我认为它应该在页面级恢复语句之前工作,它错误地说:

消息 4346,级别 16,状态 1,第 35 行 RESTORE PAGE 不允许用于使用简单恢复模型或已中断日志备份链的数据库。

这是我第一次使用完整恢复模型,所以我可能做错了什么......我可以看到差异的最后一个 lsn 和事务备份之间的小差距,我猜那里有不应该。

谁能看到我在这里做错了什么?我试图遵循网络上的示例,这些示例似乎都遵循类似的模式,但我想我遗漏了什么?

小智 3

您的完整备份命令

--进行完整备份以开始新的TLogChain

将数据库 DbNameHereCorrupt 备份到磁盘 = @fullBackupPath with init, Differential;

不进行完整备份。

微分

仅与 BACKUP DATABASE 一起使用,指定数据库或文件备份应仅包含自上次完整备份以来更改的数据库或文件部分。

正如 @dbamex 提到的,完整命令和恢复命令使用不同的文件名。