SQL Server数据库损坏、检测以及简单的修复办法

简介

    在一个理想的世界中,不会存在任何数据库的损坏,就像咱们不会将一些严重意外状况列入咱们生活中的平常同样,而一旦这类事情发生,必定会对咱们的生活形成很是显著的影响,在SQL Server中也一样如此,或许几年内您没有碰见过数据库中出现这类状况,而一旦碰见这类状况,每每伴随着数据的丢失,宕机,严重甚至您自己的职业生涯也会受到影响。所以对于这类状况,咱们须要了解数据库损坏方面的知识,以便咱们可以事前准备,过后可以处理。本篇文章会对数据库损坏的缘由、现象、事前和过后的一些处理方法以及简单的修复方法进行探讨。数据库

 

数据库为何会损坏?

    在了解数据库损坏以前,首先咱们要了解SQL Server是如何将数据保存到数据文件(MDF、NDF等)。不管更新仍是插入数据,数据都须要首先在内存中的Buffer Pool驻留,而后经过CheckPoint和Lazy Writer等过程将内存中的数据持久化到磁盘。在这个过程当中,数据脏页由内存写入持久化的IO子系统,在此期间,按照IO子系统的不一样,数据可能通过这几层:服务器

  • Windows(写数据必定调用的是WINDOWS API)
  • Windows底层的中间层(杀毒软件,磁盘加密系统)
  • 网卡、路由器、交换机、光钎、网线等(若是IO子系统不是直连的话)
  • SAN控制器(若是使用了SAN)
  • RAID控制器(IO子系统作了RAID)
  • 磁盘或SSD等持久化存储器

 

    所以,数据页被写入持久化存储期间,可能通过上述列表中的几项。在经历上述过程当中,硬件环境会受到不少方面的影响,好比说电压是否稳定、断电、温度太高或太低、潮湿程度等,而软件方面,因为软件都是人写的,所以就可能存在BUG,这些均可能致使数据页在传输过程当中出现错误。多线程

   此外,影响磁盘的因素也包括电压是否稳定、灰尘等因素,这些也有可能引发磁盘坏道或总体损坏。app

   上面提到的全部因素均可以被归结为IO子系统。所以,形成数据损坏的状况绝大部分是由IO子系统引发的,还有很是很是小的几率内存芯片也会致使数据页损坏,但这部分状况微乎其微,所以不在本文的讨论之列。编辑器

    上面提到的这些致使数据损坏的缘由都属于天灾,还有一些人祸。好比说经过编辑器等手动编辑数据文件、数据库中还有须要Redo和Undo的事务时(也就是没有Clean Shutdown)删除了日志文件(一般会致使数据库质疑)。大数据

 

发现数据库损坏

    在咱们知道可能形成数据库的损坏缘由以后,接下来咱们来看SQL Server是如何监测数据库页损坏的。加密

    在SQL Server的数据库级别,能够设置页保护类型,一共有三个选项:None,CheckSum,Torn_Page_Detection,如图1所示:spa

1

图1.页保护的三种选项线程

 

    关于这三种选项,首先,请无视None,请不要在任何场景下选择该选项,该选项意味着SQL Server不对页进行保护。日志

    其次是TORN_PAGE_DETECTION,在SQL Server中,数据的最小单位是页,每一页是8K,可是对应磁盘上每每是16个512字节的扇区,若是一个页在写入持久化存储的过程当中,只写了一半的页,这就是所谓的TORN_PAGE_DETECTION,SQL Server经过每一个扇区提512字节中前2位做为元数据,总共16个扇区32位4字节的元数据(页头中标识为:m_tornBits),经过该元数据来检测是否存在部分写的TORN_PAGE,但该类型的页验证没法检测出页中的写入错误,所以在SQL Server 2005及以上版本,尽可能选择CheckSum。

    在SQL Server 2005及以上版本,引入了CheckSum,CheckSum能够理解为校验和,当数据页被写入持久化存储时,会根据页的值计算出一个4字节的CheckSum存于页头(页头中标识同为:m_tornBits),和数据在同一页中一块儿保存在数据库中。当数据从IO子系统被读取到内存中时,SQL Server会根据页内的值再次计算CheckSum,用该从新计算的CheckSum和页头中存储的CheckSum进行比对,若是比对失败,则SQL Server就会认为该页被损坏。

    由CheckSum的过程能够看出,只有在页被写入SQL Server的过程当中才会计算CheckSum,所以若是仅仅改变数据库选项的话,则页头中的该元数据并不会随之改变。

 

与IO相关的三种错误

    经过上述CheckSum的原理能够看出,SQL Server能够检测出页损坏,此时,具体的表现形式可能为下述三种错误的一种:

  • 823错误,也就是所谓的硬IO错误,能够理解为SQL Server但愿读取页,而Windows告诉SQL Server,没法读取到该页。
  • 824错误,也就是所谓的软IO错误,能够理解为SQL Server已经读取到该页,但经过计算CheckSum等值发现不匹配,所以SQL Server认为该页已经被损坏。
  • 825错误,也就是所谓Retry错误。

 

    其中, 上述823和824错误都是错误等级为24的严重错误,所以会被记录在Windows应用程序日志和SQL Server的错误日志中,而引发该错误的页会被记录在msdb.dbo.suspect_pages中。SQL Server错误日志中也会记录到出错页的编号,如图2所示。

    2

图2.824错误在SQL Server错误记录中的描述

 

    所以,若是咱们存在完善的备份的话,咱们能够经过备份进行页还原(在此再次强调一下对于DBA来讲,有”备”无患),一个简单的页还原代码如代码清单1所示。

USE [master]
RESTORE DATABASE [Corrupt_DB] PAGE='1:155' 
FROM  DISK = N'C:\xxx.bak' 
WITH  FILE = 1,  NORECOVERY,  NOUNLOAD,  STATS = 5

代码清单1.一个简单的页还原代码,从备份中还原文件ID1中的第155页

 

    记得咱们前面说的,在读取页计算校验和时出错,这既多是被写入持久化存储的页自己出错,也多是在页被读取的过程当中出错,此时SQL Server会尝试从IO子系统中再次读取该页,最多多是4次尝试,若是在4次尝试过程当中校验和经过,则会是825错误,不然是824错误。这里要注意,与823和824错误不一样的是,825错误是一个等级仅为10的信息。

    所以,因为有固定的错误编号,所以能够在SQL Server Agent中对823和824设置警报。

 

备份CheckSum

    上述页CheckSum只有在页被使用时才会被校验页的正确性。在备份数据库时,能够指定CheckSum选项来使得备份读取的页也计算校验和,从而保证了被备份的数据库是没有损坏的。在图3的备份选项咱们能够注意到这两条:

3

图3.CheckSum和Continue_After_Error选项

 

    若是启用了CheckSum,当备份过程当中发现了页校验和错误时,就会终止备份,而启用了Continue_After_Error选项的话,在检测到校验和错误时,仍然继续从而使得备份成功。

   备份若是启用了CheckSum选项,除去检测每一页的校验和以外,还会在备份完成后,对整个备份计算校验和并存储于备份头中。

   此外,对于备份,咱们还能够经过Restore Verifyonly with CheckSum来验证备份,来保证备份的数据没有被损坏。

 

DBCC CheckDB

    前面提到SQL Server发现错误的方法有两种,分别为在读取页时和在备份时(本质上也是读取页)。但若是咱们但愿对于数据一致性的检查更加的激进,那咱们应该按期使用CheckDB来检查数据的一致性,而不至于在生产时间数据被读取时才能发现错误。

    CheckDB命令会对整个数据库作全部的一致性检查。当检查对象是Master数据库时,CheckDB还会检查ResourceDB。

    CheckDB最简单的用法如代码清单2所示,在当前数据库上下文中直接执行CheckDB,将会检查当前数据库中全部的一切。

DBCC CHECKDB

代码清单2.CheckDB最简单的用法

 

    CheckDB命令在企业版中会使用多线程来进行,会对整个数据库进行一致性检查,在该过程当中,使用了内建数据库快照的方式进行,所以不会形成阻塞,但CheckDB会消耗大量的CPU、内存和IO。所以CheckDB要选择在维护窗口时间或是系统闲时进行。

    默认状况下,CheckDB命令会将输出全部的信息,但一般咱们并不关心这些信息,而是只关心错误信息,所以实际中一般给DBCC指定不显式信息的参数,如代码清单3所示。

DBCC CHECKDB WITH NO_INFOMSGS;

代码清单3.CheckDB一般搭配No_InfoMsgs参数

 

    实际上,CheckDB是一套命令的汇总,CheckDB会依次检查下述内容:

  • 初次检查系统表
  • 分配单元检查(DBCC CHECKALLOC)
  • 完整检查系统表
  • 对全部表进行一致性逻辑检查(DBCC CHECKTABLE)
  • 元数据检查(DBCC CHECKCATALOG)
  • SSB检查
  • 索引视图、XML索引等检查

 

    首先,当发现系统表损坏时,只能经过备份进行恢复(这也是为何备份除TempDB以外的系统表很是重要)。其次,在一个大数据库中,作一次CheckDB时间会很是长,维护窗口时间或系统闲时的时间可能没法Cover这段时间,那么咱们能够将CheckDB的任务分散到CHECKALLOC、DBCC CHECKTABLE、DBCC CHECKCATALOG这三个命令中。

    更多关于CheckDB的详细信息,请参阅:http://technet.microsoft.com/en-us/library/ms176064.aspx

 

数据库损坏的修复

    数据库损坏最行之有效的办法就是存在冗余数据,使用冗余数据进行恢复。所谓的冗余数据包括热备、冷备、和暖备。

    使用镜像或可用性组做为热备,当检测到错误时,能够自动进行页修复(镜像要求2008以上,可用性组是2012的功能)。镜像当主体服务器遭遇824错误时,会向镜像服务器发送请求,将损坏的页由镜像复制到主体解决该问题。对于可用性组,若是数据页是在主副本上发现的,则主副本将会向全部辅助副本发送广播,并由第一个响应的辅助副本的页来修复页错误,若是错误出如今只读辅助副本,则会向主副本请求对应的页来修复错误。在这里有一点值得注意的是,不管是哪种高可用性技术,都不会将页错误散播到冗余数据中,由于SQL Server中全部的高可用性技术都是基于日志,而不是数据页。

    其次是使用暖备或冷备来还原页,我已经在代码清单1中给出了详细的代码,这里就不细说了。

    若是没有合适的备份存在,若是损坏的数据页是存在于非汇集索引上,那么你很幸运,只须要将索引禁用后重建便可。

    若是存在基准的完整备份,而且日志链没有断裂(包括差别备份能够Cover日志缺失的部分),则能够经过备份尾端日以后还原数据库来进行修复。

    最后,若是基础工做作的并很差,您可能就须要经过损失数据的方式来换回数据库的一致性,咱们能够经过DBCC CheckDB命令的REPAIR_ALLOW_DATA_LOSS来修复数据库。使用该方法可能致使数据损失,也可能不会致使数据损失,但大部分状况都会经过删除数据来修复一致性。使用REPAIR_ALLOW_DATA_LOSS须要将数据库设置为单用户模式,这意味着宕机时间。

    不管是哪一种状况修复数据库,都要考虑是否知足SLA,若是出现了问题以后,发现不管用哪一种方式都没法知足SLA的话,那只能反省以前的准备工做并祈祷你不会所以丢了工做。

 

小结

    本篇文章阐述了数据库损坏的概念、SQL Server检测损坏的原理、CheckDB的原理及必要性和简单的修复手段。对于数据库损坏事前要作好充足的准备,在过后才不会后悔莫及。就像买保险同样,你可不会但愿出了事之后再去买保险吧?

相关文章
相关标签/搜索