SQL Server 损坏修复 您所在的位置:网站首页 sqlserver修复有效路径 SQL Server 损坏修复

SQL Server 损坏修复

2024-07-12 01:30| 来源: 网络整理| 查看: 265

目录:

一. 常见错误解读

二. DBCC CHECKDB

三 .不同部位损坏的应对

四. Database Mirroring和AlwaysOn的页面自动修复功能

一 常见错误解读

SQL Server 对数据库损坏的错误类型做了细化,在此对几个典型的错误作一下介绍。

错误信息是:“在文件 '%ls'中、偏移量为 %#016I64x 的位置执行 %S_MSG 期间,操作系统已经向 SQL Server 返回了错误 %ls。”

“The operating systemreturned error %ls to SQL Server during a %S_MSGat offset %#016I64x in file '%ls'.”

例如:

Msg 823, Level 24, State 3, Line 1

The operating system returned error 5(Access is denied.) to SQLServer during a write at offset 0x0000000000e000 in file 'FilePath\FileName'.

823错误代表SQLServer在向操作系统申请某个页面读写的时候遇到Windows读取或写入请求失败。Windows返回的错误代码和相应的文本会插入消息中。对于读取操作,SQL Server在报出823错误之前已经重试读取请求4次。

从错误产生的机制可以看出,823错误是发出一个页面读写请求时发生的,和读写的内容没有关系。所以823错误和SQLServer本身无关。通常是物理文件损坏导致此错误,但也可能是设备驱动程序导致的。如果某个数据文件上反复出现823错误,要不就是硬件设备出了问题,要不就是数据文件已经发生了非常严重的损坏。这个错误基本上意味着数据页里的有效数据已经丢失,一般DBCCCHECKDB很难修复。

错误信息是:“SQLServer检测到基于一致性的逻辑I/O错误 %ls。在文件 '%ls' 中、偏移量为 %#016I64x 的位置对数据库 ID %d 中的页 %S_PGID 执行 %S_MSG 期间,发生了该错误。”

“SQL Server detecteda logical consistency-based I/O error: %ls. It occurred during a %S_MSG of page %S_PGIDin database ID %d at offset %#016I64x in file '%ls'.”

例如:

SQL Server detected a logical consistency-based I/O error: tornpage (expected signature: 0x0; actual signature: 0x4e0372a8). It occurredduring a read of page (1:0) in database ID 13 at offset 0000000000000000 infile 'S:\Microsoft SQL Server\MSSQL.1\MSSQL\Data\www71_global_Data.mdf'.

此错误表明Windows报告已从磁盘成功读取页,但SQL Server检测到页中存在逻辑错误。那么SQLServer会检测到哪些“逻辑错误”呢?常见的错误类型有以下几种。

Checksum

SQL Server可以在写入每个页面时,根据页面里的数据算出一个校验值,一同存储到页面里去。当下次读取页面的时候,再根据这次读到的页面数据,算出一个新的校验值。如果写入和读出的数据一模一样,那么两个校验值一定是相等的。而如果两个校验值不相等,意味着上次SQLServer写入的数据和这次读出来的内容一定不同,现在读出来的数据有问题。通过这种方法,SQL Server能够发现数据页面损坏。

TornPage

残缺页(Torn Page)保护其实是一种对电源故障导致的页损坏进行检测的方法。例如,意外电源故障可能导致一个页面只有一部分被写入了磁盘。使用残缺页保护时,页的每个512B扇区末尾会放置一个2位签名(在将原来的2位复制到页头之后)。每次进行写操作时,这个签名在二进制数01和10之间交替,这样始终可以确定是否只有部分扇区写到磁盘。如果稍后读取页时发现某个位的状态不正确,则说明该页没有被正确写入,因此检测到问题页面,称为残缺页。相对于Checksum,残缺页检测使用的资源最少,但是它的算法太简单,无法检测到磁盘硬件故障导致的所有错误。

ShortTransfer

读到的数据长度比预期的少。例如,一个读取要求预期可以读到8KB的数据,可是实际只返回了4 KB。这也意味着当前读到的页面有损坏。

Bad PageId

在读到页面后,SQL Server会比较页面开头存储的页面编号和自己请求的目标编号。如果发现自己想要读取的页面是第200页,而读到的内容里显示它是第100页,SQL Server就会触发824错误。这种错误经常是因为I/O子系统没有正确地处理SQL Server的请求,传给SQL Server一个错误的页面,甚至是一个空页面。

RestorePending

在SQL Server 的企业版里,用户可以要求在做还原的时候跳过一些有损坏的页面(continue after error)。这些跳过的页面就被标识成“Restore Pending”。如果有用户想去访问它,也会遇到824错误。

StaleRead

一些硬件系统经常发生漏写的现象(SQL Server要求将某个页面写入硬盘文件,I/O子系统报告写入已经完成,可是SQLServer下次读取的时候,读到的还是写入前的内容)。由于读到的老版本页面本身没有什么问题,Checksum和Tong Page算法都不能检查到错误。对这一类问题,SQLServer也有对策。在打开SQL Server启动参数开关-T818以后,SQL Server会在内存里维护一个哈希表,记录下自己所有做过写入动作的页面最新的LSN(Log Sequence Number)值。在下次读出页面的时候,会去比较这两个值是否相等。由于LSN是个自动增长的唯一值,每个发生新修改的页面,LSN的值会比原来的要大。所以如果读到的LSN与内存中存放的不一致,就说明上次的写入请求没有真正完成。这时824错误也会被触发。

从上面的介绍可以看出,824虽然是一个“逻辑错误”,是SQLServer主动发现的数据损坏,但是损坏的来源,大都不是SQL Server自己。这里的错误,主要是由于预期的写入没有完全完成导致的。所以824错误的原因,基本上还是在I/O子系统。由于SQL Server的读写请求是发给Windows,再由Windows发给底层的磁盘系统的,所以问题有可能发生在Windows以下的每一层,例如磁盘驱动器存在故障、磁盘固件存在问题、设备驱动程序不正确等。可以负责任地说,SQLServer自己是不会导致824错误的。

由于824错误是发生在页面这一级的逻辑错误,所以很多时候DBCC CHECKDB能够修复。但是这种修复也仅仅是逻辑上的,页面里面存储的数据在824错误发生之前就已经丢失,SQL Server无法将它们修复回来。所以824错误基本也意味着部分数据丢失。

错误信息是:“尝试在数据库%d 中提取逻辑页 %S_PGID 失败。该逻辑页属于分配单元%I64d,而非 %I64d。”

“Attempt to fetchlogical page %S_PGIDin database %d failed. It belongs to allocation unit %I64d not to %I64d.”

例如:

Attempt to fetch logical page (1:584) in database 2 failed. Itbelongs to allocation unit 445237904015360 not to 72057594060079104.

605也是一个非常有名的数据库损坏错误。此错误通常表示指定数据库中的页或分配已损坏。SQLServer会在根据页链接或使用索引分配映射(IAM)读取属于表的页时,检测到此损坏。分配给表的所有页必须属于与该表相关联的分配单元之一。如果页眉中包含的分配单元ID不匹配与表相关联的分配单元ID,将引发此异常。错误消息中列出的第一个分配单元ID是页眉中显示的ID,而第二个分配单元值则是与表相关联的ID。

严重级别为21表示可能存在数据损坏。造成的原因包括损坏的页链、损坏的IAM或该对象的sys.objects目录视图中存在无效条目。这些错误通常由硬件或磁盘设备驱动程序故障而引起。

严重级别为12表示可能存在暂时性错误,即在缓存中出现错误,但不表示对磁盘上的数据造成破坏。暂时性的605错误可由以下条件引发:

操作系统过早地通知SQL Server已完成某个I/O操作;尽管不存在实际的数据损坏,但显示错误消息。 运行带有优化器提示NOLOCK的查询,或将事务隔离级别设置为READ UNCOMMITTED。当使用NOLOCK或READ UNCOMMITTED的查询尝试读取被其他用户移走或更改的数据时,将发生605错误。若要验证是否为暂时性的605错误,可以稍后重新运行该查询。

通常,如果在数据访问期间发生该错误,但后续的DBCCCHECKDB操作在没有出错的情况下完成,则605错误可能是暂时的。

由于605这个错误意味着一些页面分配出了问题,所以也是一个非常严重的数据库损坏。一般用DBCC CHECKDB也很难修复。

其他

在SQL Server内部,除了文件页面分配和每个页面内部格式以外,还有一些其他的约束规则。下面是一些常见的错误例子。

PFS页面头有损坏:

Msg 8946, Level 16, State 12, Line 1Table error: Allocation page(1:13280496) has

invalid PFS_PAGEpage header values.Type is 0. Check type, alloc unit ID and page

ID on the page.

系统表上的聚集索引页面上有损坏:

Server: Msg 8966, Level 16, State 1, Line 1 Could not read andlatch page (1:18645)

with latch type SH. sysindexes failed.

Msg 7985, Level 16, State 2, Server SUNART, Line 1System tablepre-checks: Object

ID 4. Could not read and latch page (1:51) withlatch type SH. Checkstatement

terminated due to unrepairable error.

某个字段的值不符合字段数据类型定义:

Msg 2570, Level 16, State 3, Line 1Page (1:152), slot 0 in objectID 2073058421,

index ID 0, partition ID 72057594038321152, alloc unit ID72057594042318848 (type

"In-row data"). Column "c1" value is out ofrange for data type "datetime". Update

column to a legal value.

元数据有损坏:

Msg 3854, Level 16, State 1, Line 2Attribute (referenced_major_id=2089058478)of

row (class=0,object_id=2105058535,column_id=0,referenced_major_id=2089058478,referenced_

minor_id=0)in sys.sql_dependencies has amatching row (object_id=2089058478)in

sys.objects (type=SN) that is invalid.

遇到这些错误,管理员需要用DBCCCHECKDB命令来检查和修复。有些错误是可以不丢数据就能修复的,有些是要丢数据才能修复物理层面错误的,有些是即使丢数据也没办法修复的。现在就来介绍CHECKDB的使用技巧。

SQL Server 损坏修复 之二 DBCC CHECKDB

DBCC CHECKDB指令可以完成两项任务:(1)检查数据库里有没有损坏发生。(2)尽力修复数据库损坏,使数据能够重新被正常访问。所以哪怕是一个正常运行的数据库,也建议定期运行这句指令,以确保没有损坏发生。对于已经发生访问错误的数据库,应该在第一时间运行这句指令,了解损坏的范围和程度。

那么DBCCCHECKDB究竟做了哪些检查呢?

在做些什么

DBCC CHECKDB通过依次执行下列操作检查指定数据库中所有对象的逻辑和物理完整性:

检查一些关键的系统表。 对数据库运行DBCC CHECKALLOC。 对数据库中的每个表和视图运行DBCC CHECKTABLE。 对数据库运行DBCC CHECKCATALOG。 验证数据库中每个索引视图的内容。 验证数据库中的Service Broker数据。

这意味着运行了DBCC CHECKDB,就不必再单独运行DBCC CHECKALLOC、DBCCCHECKTABLE或DBCC CHECKCATALOG命令。也意味着单独运行DBCCCHECKALLOC、DBCC CHECKTABLE和DBCCCHECKCATALOG命令,虽然不能完全完成DBCC CHECKDB的所有功能,但是至少完成了大部分功能。

检查一些关键系统表

在检查数据库之前,SQLServer需要去了解这个数据库里到底存放了什么样的数据,也就是所谓数据库的“元数据”(Metadata)。没有这些信息,SQL Server无法知道自己将要去访问什么样的表格,也没办法知道自己应该怎么解释将要读到的记录。

关键系统表有:

sysallocunits。

syshobts。

syshobtcolumnes。

sysrowsets。

sysrowsetcolumns。

对于普通用户访问,这些表都是不可见的。只有在DAC模式下的连接,才能看到它们。它们的结构对普通用户也是透明的。

这里的每一张系统表都有一个聚集索引。SQLServer会像做CHECKTABLE一样,对这些系统表做一遍检查,确保这些表格里的每一页面及页面里的每一条数据都可以正确地读出来。如果中间发现问题,例如发现某个页面不能被正常访问,SQLServer就会报错。例如:

Server: Msg 8966, Level 16, State 1, Line 1

Could not read and latch page (1:33245) with latch type SH.Sysobjects failed.

对于小的数据库,这些存放元数据库的系统表不会占用太多的页面。如果发生硬件问题,损坏的几率比较小。但是对一些有成千上万对象的数据库,这些原数据系统表本身就可能使用了很多页面,发生损坏的几率也随之增大。由于这些系统表是正确读取一切数据的根本,所以如果任意一张系统表上发生了损坏,DBCCCHECKDB都会直接失败,数据库也无法做任何修复。此时恢复数据库的唯一方法,只有恢复数据库的备份。

对数据库运行DBCC CHECKALLOC

DBCC CHECKALLOC将检查数据库中所有页的分配。它还可验证各种内部结构,这些结构可用于跟踪这些页,以及它们之间的关系。

DBCC CHECKALLOC将返回以下结果集(值可能有所不同,我们以AdventureWorks数据库为范例)。

DBCC results for 'AdventureWorks'. *************************************************************** Table sys.sysrowsetcolumns Object ID 4. Index ID 1, partition ID 262144, alloc unit ID 262144 (type In-rowdata). FirstIAM (1:139). Root (1:66). Dpages 0. Index ID 1, partition ID 262144, alloc unit ID 262144 (type In-rowdata). 13 pages used in 1 dedicated extents. Total number of extents is 1. *************************************************************** '...' *************************************************************** Table Production.TransactionHistoryArchive Object ID 158623608. Index ID 1, partition ID 72057594047037440, alloc unit ID72057594053459968 (type In-row data). FirstIAM (1:804). Root (1:6568). Dpages0. Index ID 1, partition ID 72057594047037440, alloc unit ID72057594053459968 (type In-row data). 622 pages used in 79 dedicated extents. Index ID 2, partition ID 72057594052804608, alloc unit ID72057594059227136 (type In-row data). FirstIAM (1:2897). Root (1:12608). Dpages122. Index ID 2, partition ID 72057594052804608, alloc unit ID72057594059227136 (type In-row data). 124 pages used in 17 dedicated extents. Index ID 3, partition ID 72057594052870144, alloc unit ID72057594059292672 (type In-row data). FirstIAM (1:2899). Root (1:12832). Dpages166. Index ID 3, partition ID 72057594052870144, alloc unit ID72057594059292672 (type In-row data). 168 pages used in 22 dedicated extents. Total number of extents is 118.

--对于每一个表格对象,检查它每个索引上的每个分区的数据分配情况

'...' Processed 317 entries insystem catalog for database ID 5. File 1. The number ofextents = 2898, used pages = 22552, and reserved pages = 23179. File 1 (number of mixed extents =104, mixed pages = 827). Object ID 4, index ID 1, partition ID262144, alloc unit ID 262144 (type In-row data), data extents 1, pages 13,mixed extent pages 9. '...'

--对于每个数据文件,检查上面的数据页面分配情况

The total number of extents= 2898, used pages = 22552, and reserved pages = 23179 in this database. (number of mixed extents = 104, mixedpages = 827) in this database. CHECKALLOC found 0allocation errors and 0 consistency errors in database 'AdventureWorks'. DBCC execution completed.If DBCC printed error messages, contact your system administrator.

-- 对于整个数据库的总结

对数据库中的每个表和视图运行DBCC CHECKTABLE

对于指定的表,DBCCCHECKTABLE将检查以下内容:

是否已正确链接索引、行内、LOB及行溢出数据页。 索引是否按照正确的顺序排列。 各指针是否一致。 每页上的数据是否合理(包括计算列)。 页面偏移量是否合理。 基表的每一行是否在每个非聚集索引中具有匹配的行,以及非聚集索引的每一行是否在基表中具有匹配的行。 已分区表或索引的每一行是否都位于正确的分区中。

DBCC CHECKTABLE返回以下正确结果集。

DBCC results for 'HumanResources.Employee'.

There are 288 rows in 13 pages for object 'Employee'.

DBCC execution completed. If DBCC printed error messages, contactyour system administrator.

对数据库运行DBCC CHECKCATALOG

检查指定数据库系统表里记录的元数据逻辑一致性。可能的错误例如:

Attribute (object_id=130099504)of row (object_id=130099504,column_id=1) in

sys.columns does not have a matching row (object_id=130099504) in sys.objects.

--在sys.columns视图里,有一个列不属于sys.objects里的任何一个表格或视图

Attribute (referenced_object_id=130099504,key_index_id=2) of row

(object_id=1447012236)in sys.foreign_keysdoes not have a matching row

(object_id=130099504,index_id=2) in sys.indexes.

--在外键视图sys.foreign_keys里的一个外键在sys.indexes里找不到对应的索引

Attribute (parent_object_id=130099504) of row (object_id=2061966422) in sys.objects does not have a matchingrow (object_id=130099504) insys.objects.

--某个对象的父对象不存在。(例如有一个主键对象存在,但是主键所依附的表格不存在了。)

这些错误在正常的数据库里不应该出现,除非用户自己去直接修改了系统表里的数据。

验证数据库中每个索引视图的内容

SQL Server支持在某些视图上建立索引,以提高视图的性能。在视图中一些经过计算才能得到的字段值,SQLServer会将它们存储在索引页面里。下次可以直接使用,而不需要再做计算。

DBCC CHECKDB会将视图再计算一遍,验证索引页面里存储的字段值都是正确的,从而保证索引视图的数据可靠性。但是如果视图查询的源数据量非常大,CHECKDB会使用tempdb里的空间协助计算。这个过程会比较消耗资源和时间。如果想要跳过这一步,可以使用PHYSICAL_ONLY这个参数。

由于索引页里的数据都是根据源数据计算出来的,如果CHECKDB发现有任何问题,修复起来还是比较容易的。只要把现有的有错误的数据删除,新计算一遍重新存储起来就可以。所以索引视图上的问题一般不会导致数据丢失。

对于XML字段上建立的索引,SQL Server在这一步也会做类似的验证。

验证数据库中的Service Broker数据

如果数据库使用了ServiceBroker的功能,SQL Server还会调用ServiceBroker的组件,检查相关的系统对象(Service Broker的queue、pipeline等)是否正常。这部分和传统的表格索引等没直接的关系。

最后,DBCCCHECKDB会打印出一句总结的话:

CHECKDB found 0allocation errors and 0 consistency errors in database 'AdventureWorks'.

如果您的数据库没有说“0allocation errors”和“0 consistency errors”,而是有若干个错误,那就意味着数据库有损坏了,赶紧修吧。

提供的修复方法

默认DBCCCHECKDB只会验证数据库是否完好,不会主动去做数据库修复动作。要尝试修复数据库,需要将数据库设成单用户模式,才能使用以下三个修复选项之一。

· REPAIR_ALLOW_DATA_LOSS

尝试修复报告的所有错误。这些修复可能会导致一些数据丢失。

· REPAIR_FAST

保留该语法只是为了向后兼容。未执行任何修复操作,请不要使用。

· REPAIR_REBUILD

执行次要、快速修复(例如,修复非聚集索引中的额外键)及耗时修复(例如,重新生成索引)。执行这些修复时不会有丢失数据的危险。

如果已通过使用ALTERDATABASE语句将数据库设置为紧急模式,那么假如指定了REPAIR_ALLOW_DATA_LOSS选项,则DBCC CHECKDB可以对数据库执行某些特殊修复,恢复的数据库在物理层面的一致性,使其能够重新访问。但是这种修复是以丢失数据为前提的。所以应当是最后手段,并只有在无法从备份还原数据库时才采用。

将数据库设成紧急模式并以REPAIR_ALLOW_DATA_LOSS子句运行DBCC CHECKDB时,将执行以下操作

将由于I/O或校验错误而被标记为不可访问的页重新标记为可访问,就如同这些错误没有出现过一样。这样用户将能够访问这些页面,虽然页面里的内容肯定有问题。 将尝试使用常规的基于日志的恢复技术恢复数据库。 如果由于事务日志损坏而导致数据库恢复失败,则将重建事务日志。但是重建事务日志可能会导致数据库里的事务不一致。

如果DBCCCHECKDB命令成功,则说明数据库在物理结构上是正确的,并且数据库状态将设置为ONLINE,用户可以正常访问。但是,数据库可能包含一种或多种事务不一致的情况。修复操作也不会考虑表本身或表之间可能存在的任何约束。如果指定的表与一个或多个约束有关,建议在修复操作后运行DBCCCHECKCONSTRAINTS。如果必须使用REPAIR,则运行不带有修复选项的DBCCCHECKDB来查找要使用的修复级别。如果必须使用REPAIR_ALLOW_DATA_LOSS级别,则建议在运行带有此选项的DBCC CHECKDB之前备份数据库。因为DBCCCHECKDB造成的修改,用户可能会无法接受,而这个时候也没办法再用备份恢复的方法恢复数据库了。

对于REPAIR_ALLOW_DATA_LOSS,这里的data loss不仅仅是指一些数据记录可能被删除,还指有些错误的记录会保留在数据库里,让用户继续使用。所以其实这是一种比较危险的选择,只能在万不得已的时候选用。

如果一个数据库使用REPAIR_ALLOW_DATA_LOSS级别都不能修复,管理员又能怎么办呢?选择真的十分有限。以下是可用的几种方法:

(1)按照预先的备份恢复策略,恢复数据库备份。

这个可以说是最好的办法,能够将数据库恢复到一个一致的时间点。强烈建议管理员使用这个选择。

(2)如果损坏发生在某些用户对象上(用户表、视图、存储过程等),可以把它们DROP掉试试。

(3)将数据库设成紧急只读模式,用“SELECT ... INTO”或其他方式,将数据导入到一个新建的空数据库里。

设置紧急模式的指令是:

ALTER DATABASE SET EMERGENCY

这种方法能够从数据库中将所有能读出来的数据都读出来,挽救尽可能多的数据。但是损坏严重程度不一样,丢的数据多少也不一样。这样救回来的数据库各个数据表的状态将会不一致,一般在逻辑上会有很大的问题。

还是老生常谈,恢复备份永远是最好的选择。

许多用户在运行DBCCCHECKDB之前有很大的顾虑,担心CHECKDB会造成数据库阻塞,严重影响正常的应用运行。在前面的章节里也介绍了,CHECKDB的过程其实是一个比较复杂的过程,SQL Server为了验证一个数据库的正确性,要做的事情还是非常多的。运行它而造成一些性能影响,也是难免的。另一方面,许多数据库损坏是无法修复,或者虽然可以在物理上修复,但是逻辑上的错误是无法挽回的。如果等到用户访问数据的时候才发现数据库损坏,可能已经为时已晚,损失巨大了。所以对每个数据库定期做CHECKDB工作,必须是数据库管理员的日常工作之一。那么管理员怎样在这两者之间平衡,既能够有一个比较合理的周期CHECKDB,又尽量不影响数据库应用性能呢?

首先,SQL Server作为一个能够支持超大数据库的数据库管理系统,在DBCC CHECKDB上不断地改进着。在现在的应用中,数百GB以至上TB的SQL Server数据库比比皆是。不是说有用户在使用数据库,就不能运行CHECKDB的。SQL Server通过下面这些技术大大提高了CHECKDB的速度,降低了它对并发用户的影响,防止了阻塞。

内部数据库快照

在执行DBCCCHECKDB命令时,数据库引擎创建一个数据库快照,并将其置于在事务上一致的状态。然后,DBCC命令对该快照运行检查,而不是对数据库本身做检查。DBCC命令完成后,将删除该快照。这样,CHECKDB命令就不需要申请许多锁,可以良好地防止在执行时出现阻塞和并发问题。所以从阻塞的角度讲,CHECKDB完全可以在多用户的模式下正常使用,不需要等到一个所有用户都离线的时候再做。

并行检查对象

默认情况下,DBCCCHECKTABLE对对象执行多个线程并行检查,以加快检查速度。并行度由查询处理器自动确定。最大并行度的配置与配置并行查询相同。若要限制DBCC检查可使用的处理器的最大数目,请使用sp_configure改变maxdegree of parallelism选项。

并行度其实是一把双刃剑。越多的处理器在同时进行数据库检查,CHECKDB能够完成得越快。可是在这段时间里,就会有越多的系统资源被使用在CHECKDB上。其他同时在运行的连接可能就拿不到足够的资源,性能反而会受到更大的影响。所以管理员需要根据具体情况,在两者之间做一个平衡。决定是尽快完成CHECKDB更重要呢,还是要兼顾其他连接的性能。通过使用跟踪标志2528,可以禁用并行检查。

PHYSICAL_ONLY

这个选项可以以较小的开销检查数据库的物理一致性,并且能检测出会危及用户数据安全的残缺页、校验和错误及常见的硬件故障。但对于有些检查会忽略,如FILESTREAM数据。因此,针对生产系统中频繁使用的情况,建议使用PHYSICAL_ONLY选项。使用PHYSICAL_ONLY选项可以极大地缩短对大型数据库运行DBCC CHECKDB的时间。

既然有了这些技术,那么现在SQLServer运行一次CHECKDB大概要多久呢?很不幸,这真是一个非常难以回答的问题。运行的时间和下面这些因素有关系。

(1)数据库自身大小。

(2)当前系统I/O子系统的读写能力与繁忙程度。

CHECKDB需要把数据库从头到尾通读一遍。这本身就是一个巨大的I/O工作。I/O子系统能多快地完成SQL Server提出的读写请求,是影响到CHECKDB速度的最重要的因素。

(3)当前系统CPU负荷。

CHECKDB本身也是个验证工作。让计算机去验证什么事情,就意味着让CPU去做计算。所以有时候CHECKDB也会导致系统CPU负载加重。

(4)当前数据库的并发修改量。

虽然SQL Server使用快照技术大大提高了数据库运行CHECKDB时候的并发度,但是如果数据库上的修改非常频繁,快照数据库的维护本身会是一个很耗资源的任务,会反过来影响CHECKDB的速度。

(5)存放tempdb磁盘的速度。

当数据库非常大的时候,SQLServer需要很多内存来存放一些中间结果。有时候仅放在内存里是不合适也是不可能的,需要借助tempdb里的空间。那么tempdb磁盘的读写速度对CHECKDB的速度也会有显著影响。

(6)数据库里对象的类型。

不同类型的对象,需要验证其正确性所花费的代价是不一样的。比较费资源的对象有非聚集索引、计算列(computed column)、off-rowLOB values、Service Broker、XML索引、索引视图(indexed view)等。如果这些对象在一个数据库里使用得比较多,那么同样的大小,这样的数据库CHECKDB会更耗时一些。

(7)CHECKDB使用的参数。

有些参数可以让SQL Server少做一些检查。例如WITH NOINDEX可以让SQL Server不用去做费时费力的非聚集索引检查。WITH PHYSICAL_ONLY可以让SQLServer只做物理结构完整性检查等。

(8)数据库里面的错误类型和错误的数目。

如果SQL Server在CHECKDB的过程中发现了错误,它就会用更加复杂的算法来衡量错误的性质、范围和影响,以便将最准确有用的信息返回。这会使得CHECKDB的时间大大延长。

根据2012年时的经验,一个大于1 TB的数据库如果没有错误,CHECKDB在有些机器上用8小时就能够跑完。而一个有成百上千错误的数据库,哪怕只有两三百GB,也有可能一天都跑不完。这个区别是很显著的。

虽然比较难以估计做一个DBCCCHECKDB需要多长时间,但是读者可以通过下面的语句,查询做DBCC CHECKDB进度如何。有时候进度可能不太精确,但是我们至少心里有数大概什么时候能够做完。

SELECT session_id,request_id, percent_complete, estimated_completion_time ,

DATEADD(ms,estimated_completion_time,GETDATE())AS EstimatedEndTime,

start_time, status,command

FROM sys.dm_exec_requests

WHERE command like '%DBCC%'

超大数据库上的最佳实践

谈了半天,结论还是两个:对超大数据库,CHECKDB本身是一个比较昂贵的任务,可能会影响并行运行的其他连接的性能;而不运行CHECKDB又是很危险的,如果长期不运行,突然发现已经积累了很多错误,这种风险几乎无法承担。那么怎么安排好这个任务呢?

如果数据库里设计了分区表(partitionedtable)机制,做起来可能比较简单一些。对于存储历史数据的分区文件组,由于数据本身已经不会发生修改,我们可以把文件组类型设成只读模式,防止任何误修改。每个月或者每两个星期对它们运行一次DBCCCHECKFILEGROUP即可。对于当前的数据,由于随时都可能发生读写,发生损坏的几率也高得多。所以可以每个星期,甚至一个星期两次,单独做DBCCCHECKFILEGROUP。

如果数据库没有分区机制,CHECKDB就是一个宏大的工程了。几乎可以说,没有机会让管理员找到一个时间窗口能把一个完整的CHECKDB做完。这时候怎么做呢?

有一种折中的方法,是把数据库里面的所有表格按照它们占用的页面数量大致分为7组,每组的页面数目大致一样。然后按照这样的方式把CHECKDB里面的关键任务分散在每天运行。

周一到周三:

每天运行一组DBCCCHECKTABLE。

周四:

DBCC CHECKALLOC + 一组DBCCCHECKTABLE。

周五周六:

每天运行一组DBCCCHECKTABLE。

周日:

DBCC CHECKALLOC + DBCC CHECKCATALOG + 一组DBCC CHECKTABLE。

用这种方法,可以在代价比较小的前提下完成CHECKDB的大部分工作。TB级数据库的管理员可以考虑试试。

如果您有一台备用服务器,则可以考虑不在生产环境上运行DBCCCHECKDB。而是把生产环境的数据库通过备份方式,还原到备用服务器上,在备用服务器运行DBCCCHECKDB。如果备用服务器上检查结果数据是完整的,这说明在对生产环境数据库做备份的那一刻,数据是完整的。如果备用服务器上执行的结果显示数据完整性有问题,则一定要在生产环境再次运行DBCCCHECKDB,以明确问题到底出在哪个环节。是生产环境的数据已经有问题,还是还原到备用服务器时出问题。这时候检查数据完整性的优先级高于性能影响。所以在生产环境再次运行DBCCCHECKDB是必须的。使用这种方法的缺点是,需要额外一台服务器,以及比较完善的自动化执行方案。

三 不同部位损坏的应对

如果数据库或数据库备份受损,在检查数据库完整性的时候,会发现各种各样的错误。在这一节里,我们针对不同的损坏部位,给出不同的应对方法。首先,我们创建一个测试数据库。

CREATE DATABASE TESTDB GO USE TESTDB GO CREATE TABLE TESTTABLE (ID int, NAME nvarchar(50) )

--建立两个索引,其中一个是聚集索引,另外一个是非聚集索引

CREATE CLUSTERED INDEX idx1 on TESTTABLE (ID)

CREATE INDEX idx2 on TESTTABLE(NAME)

-- 插入300行数据

DECLARE @i INT SET @i = 1 WHILE (@i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有