解决方法
干得好:
只有一次你应该尝试计算CHECKDB要花多长时间 – 当你计划定期数据库维护时.如果您遇到了腐败(或可疑的损坏)数据库,并且您只是开始考虑CHECKDB将要花多长时间 – 您在规划灾难恢复策略时犯了一个错误.您始终需要知道CHECKDB(平均)为数据库运行需要多长时间,因此:
>您可以判断特定的CHECKDB运行时间是否比平时更长 – 这表明它发现了一些损坏
>您知道在灾难恢复情况下获得结果需要多长时间
在我去的每个会议上,有人问我CHECKDB将在他们的数据库上运行多长时间.我有几种方法可以回答这个问题:
>无益的答案 – 我不知道.
>几乎有用的答案 – 上次运行需要多长时间并且条件完全相同?
>我通常给出的答案 – 这取决于.
现在,很多人会认为第三个答案与第一个答案有些相同 – 没有帮助.问题是有很多因素会影响CHECKDB运行的时间.让我解释十个最重要的因素,以便您了解为什么这实际上是一个有用的答案.这些没有任何特别重要的顺序.
>数据库的大小
非常明显…… CHECKDB必须读取数据库中每个已分配的页面,因此它越大,读取所有页面所需的时间就越长.
>服务器上的并发IO负载
在最简单的层面上,CHECKDB会做什么?它读取数据库中的每个已分配页面.这是很多IO. CHECKDB非常努力地做最有效的IO,并以其物理顺序读取数据库页面,并有足够的预读,这样磁盘磁头就可以平滑地移动到磁盘上(而不是随机跳转并导致磁盘磁头寻找延迟).如果服务器上没有并发IO负载,那么IO将和CHECKDB一样高效.但是,从sql Server引入任何额外的IO意味着磁头将跳转 – 减慢CHECKDB IO.如果IO子系统的容量已经来自CHECKDB的IO需求,那么任何额外的IO都将减少CHECKDB可用的IO带宽 – 减慢速度.
>服务器上的并发cpu活动
在简单的下一级,CHECKDB将以某种方式处理它读取的每个页面.根据您指定的各种选项和数据库架构(下面的详细信息),这将使用大量cpu – 当CHECKDB运行时,服务器可能会以100%cpu挂钩.如果服务器上有任何额外的工作负载,这将使cpu周期远离CHECKDB,并且会减慢它的速度.
基本上,#2和#3所说的是CHECKDB非常耗费资源!它可能是您可以要求sql Server执行的资源最密集的事情之一,因此在高峰工作负载时间内不运行它通常是一个好主意,因为您不仅会导致CHECKDB运行更长时间,还会减慢并发工作负载,可能无法接受.
>数据库上的并发更新活动
这与sql 2000和sql 2005都有关,但原因各不相同.
在sql 2000中,CHECKDB从并发DML事务的事务日志分析中获取其数据库的一致视图(有关详细信息,请参见此处). CHECKDB运行时,并发DML越多,生成的事务日志就越多 – 因此CHECKDB分析该事务日志所需的时间越长.在一个大型多cpu盒子上,有大量并发DML和CHECKDB仅限于一个cpu,这个CHECKDB阶段可能比读取和处理数据库页面要长几倍! (我已经多次在现实生活中看到过这种情况.)
在sql 2005中,CHECKDB从数据库快照获取其数据库的一致视图,该快照存储在与数据库本身相同的磁盘卷上.如果在CHECKDB运行时数据库中有很多更改,则更改的页面将被推送到快照,以使其保持一致.由于快照文件存储在与数据库文件相同的位置,因此每次将页面推送到快照时,磁头都必须移动,这会中断#2中描述的高效IO.此外,每当CHECKDB去读取页面并且需要从快照文件而不是数据库文件中读取页面时,这是另一个磁头移动,以及另一个有效的IO中断.对数据库的并发更改越多,高效IO的中断越多,CHECKDB运行的速度就越慢.
> IO子系统的吞吐量功能
这一个很简单. CHECKDB将进行IO加载,它甚至可能最终被IO限制(意味着cpu周期性地等待IO完成),具体取决于指定的选项和数据库模式.这意味着IO子系统的吞吐量将直接影响CHECKDB的运行时.所以,如果你有一个1TB数据库并且IO子系统只能管理100MB /秒,那么只需要3个小时来读取数据库(1TB / 100MB / 3600秒)并且你无法做任何事情来加快速度.升级IO子系统.
我已经失去了多次我听到客户抱怨CHECKDB(或索引重建或其他IO重型操作)只是发现磁盘队列长度很大并且IO子系统完全无法匹配的次数服务器和工作量.
>包装盒上的cpu数(处理核心数)
这也真正包含了正在运行的sql Server版本.在Enterprise Edition中,CHECKDB可以在框中的所有cpu上并行运行(或者在编译CHECKDB内部查询时,查询处理器决定并行化多个).并行运行可以显着提高CHECKDB的性能并缩短运行时间,只要数据库也分布在多个文件上(因此IO可以并行化).有一个漂亮的算法可以让CHECKDB并行运行,我将在以后的文章中详细解释.
另一方面,CHECKDB可以在Enterprise Edition中并行运行这一事实对于某些情况可能不好,因此一些DBA选择强制CHECKDB为单线程. SAP通常建议这样做有助于提高用户查询的可预测性.执行此操作的方法是打开记录的跟踪标志2528.
>放置tempdb的磁盘的速度
针对VLDB运行CHECKDB会为内部状态使用大量内存,对于VLDB,内存要求通常会超出sql Server可用的内存量.在这种情况下,状态被假脱机到tempdb,因此tempdb的性能可能是CHECKDB性能的关键因素.有关此内容的更多详细信息,请参阅此文章,以及如果tempdb太小,CHECKDB如何耗尽磁盘空间.
>数据库模式的复杂性
这可能会对CHECKDB的运行时产生很大的影响,因为它会影响CHECKDB所需的cpu数量.例如,CHECKDB执行的最昂贵的检查是针对非聚集索引的.它需要检查非聚集索引中的每一行是否恰好映射到表的堆中的一行或聚簇索引,并且每个堆/聚簇索引行在每个非聚簇索引中只有一个匹配的行.虽然有一个高效的算法,但它仍然需要CHECKDB使用的总cpu的30%左右!
只有在数据库中使用了这些功能时,才会进行许多其他检查 – 例如计算列评估,行外LOB值,Service Broker,XML索引,索引视图之间的链接 – 因此您可以看到经验因素不足以确定运行时.
>指定了哪些选项
这与#7几乎相同,通过指定各种选项限制CHECKDB实际执行的检查.例如,使用WITH NOINDEX选项将关闭我在#7中描述的非聚集索引检查,并使用WITH PHYSICAL_ONLY选项将关闭所有逻辑检查,大大减少CHECKDB的运行时间并使其几乎总是IO -bound而不是cpu绑定(事实上,这是VLDB的DBA用于使CHECKDB的运行时可管理的最常见选项).
有一点需要注意 – 如果指定任何修复选项,CHECKDB总是运行单线程,即使在Enterprise Edition上的多进程盒上也是如此.
>数据库中存在的损坏的数量和类型
同样,这类似于#7和#8.如果存在任何损坏,可能会触发额外的检查以试图找出损坏的更多细节.例如,对于非聚集索引检查,在没有损坏的情况下(对于绝大多数情况考虑数百万次CHECKDB在全世界每天运行的情况),该算法被大量调整.当检测到非聚集索引损坏时,必须使用更深入的算法来确定损坏的确切位置,这涉及重新扫描一堆数据,从而花费更多时间.还有一些像这样的其他算法.
现在要记住的另一件事是使用REPAIR_ALLOW_DATA_LOSS使检查运行单线程,因此修复得到正确的排序 – 这使得它运行时间更长.请查看2005 SP2上的错误日志中的消息5268 – 如上所述,它表示深入研究.
摘要
所以你可以看到没有简单的答案.希望这可以帮助!
PS忘了说在sql 2005中我向DBCC CHECKDB添加了进度报告.您可以查询sys.dm_exec_requests DMV并查找percent_complete列.