无可奈何花落去,数据丢失时时来;何当共谈完整性,却话巴山夜雨时----详解SQL Server 数据库库完整性检查和置疑修复



前情提要

数据库完整性!

这不是SQL Server独有,有点用户认为是SQL Server设计的问题出现数据库不完整,准确的告诉你,所有的数据库系统,都会存在这问题。 就是数据库出现不完整。

数据库完整性是指数据库中数据在逻辑上的一致性、正确性、有效性和相容性。SQL  Server 中完整性检查包含如下:

  • 检查指定数据库的磁盘空间分配结构的一致性。

  • 检查组成表或索引视图的所有页和结构的完整性。

  • 检查指定数据库内的目录一致性。  

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

  • 使用 FILESTREAM 在文件系统中存储 varbinary(max) 数据时,验证表元数据和文件系统目录和文件之间的链接级一致性。

  • 验证数据库中的 Service Broker 数据。

故事插曲

上周才发生,一个客户的数据库在进行了某些操作后,数据库“置疑”, 提示需要进行数据库完整性检查,所有业务都停滞了。

而客户数据库是TB级别,进行完整性检查超过8个小时。业务至少停止了10几个小时。这个客户的事件还算是特殊情况发生

另外一个客户,则是在日常日志错误已经有一些错误报告,没有任何人员进行维护工作。 某一天终于数据库质疑。也就是停止服务了,然后就是丢失数据修复....

这两个故事讲的是几乎很多客户曾经碰到的问题,日常维护工作不做完整性检查,某一天就会发生。 是时候来讲讲完整性检查

完整性检查最佳实践

命令


DBCC CHECKDB     
    [ ( database_name | database_id | 0    
        [ , NOINDEX     
        | , { REPAIR_ALLOW_DATA_LOSS | REPAIR_FAST | REPAIR_REBUILD } ]    
    ) ]    
    [ WITH     
        {    
            [ ALL_ERRORMSGS ]    
            [ , EXTENDED_LOGICAL_CHECKS ]     
            [ , NO_INFOMSGS ]    
            [ , TABLOCK ]    
            [ , ESTIMATEONLY ]    
            [ , { PHYSICAL_ONLY | DATA_PURITY } ]    
            [ , MAXDOP  = number_of_processors ]    
        }    
    ]    
]   
这看起来复杂, 
例:
DBCC CHECKDB;  --检查当前数据库
DBCC CHECKDB (AdventureWorks2012, NOINDEX);--检查  AdventureWorks2012 不检查 nonclustered indexes
DBCC CHECKDB WITH NO_INFOMSGS; --以下示例检查当前数据库,并取消所有信息性消息
DBCC CHECKDB (AdventureWorks2012,REPAIR_ALLOW_DATA_LOSS ) --允许数据丢失的修复

检查结果集如下类似:

DWConfiguration的 DBCC 结果。
Service Broker 消息 9675,状态 1: 已分析的消息类型: 14
Service Broker 消息 9676,状态 1: 已分析的服务约定: 6
Service Broker 消息 9667,状态 1: 已分析的服务: 3
Service Broker 消息 9668,状态 1: 已分析的服务队列: 3
Service Broker 消息 9669,状态 1: 已分析的会话端点: 0
Service Broker 消息 9674,状态 1: 已分析的会话组: 0
Service Broker 消息 9670,状态 1: 已分析的远程服务绑定: 0
Service Broker 消息 9605,状态 1: 已分析的会话优先级: 0
sys.sysrscols的 DBCC 结果。
对象“sys.sysrscols”在 15 页中找到 1264 行。
sys.sysrowsets的 DBCC 结果。
对象“sys.sysrowsets”在 3 页中找到 169 行。
sys.sysclones的 DBCC 结果。
对象“sys.sysclones”在 0 页中找到 0 行。
sys.sysallocunits的 DBCC 结果。
对象“sys.sysallocunits”在 3 页中找到 200 行。
sys.sysfiles1的 DBCC 结果。
对象“sys.sysfiles1”在 1 页中找到 2 行。
sys.sysseobjvalues的 DBCC 结果。
对象“sys.sysseobjvalues”在 1 页中找到 1 行。
sys.syspriorities的 DBCC 结果。
对象“sys.syspriorities”在 0 页中找到 0 行。
sys.sysdbfrag的 DBCC 结果。
对象“sys.sysdbfrag”在 0 页中找到 0 行。
sys.sysfgfrag的 DBCC 结果。
对象“sys.sysfgfrag”在 0 页中找到 0 行。
sys.sysdbfiles的 DBCC 结果。
对象“sys.sysdbfiles”在 1 页中找到 2 行。
sys.syspru的 DBCC 结果。
对象“sys.syspru”在 0 页中找到 0 行。
sys.sysbrickfiles的 DBCC 结果。
对象“sys.sysbrickfiles”在 0 页中找到 0 行。
sys.sysphfg的 DBCC 结果。
对象“sys.sysphfg”在 1 页中找到 1 行。
sys.sysprufiles的 DBCC 结果。
对象“sys.sysprufiles”在 1 页中找到 2 行。
sys.sysftinds的 DBCC 结果。
对象“sys.sysftinds”在 0 页中找到 0 行。
sys.sysowners的 DBCC 结果。
对象“sys.sysowners”在 1 页中找到 15 行。
sys.sysdbreg的 DBCC 结果。
对象“sys.sysdbreg”在 0 页中找到 0 行。
sys.sysprivs的 DBCC 结果。
对象“sys.sysprivs”在 1 页中找到 179 行。
sys.sysschobjs的 DBCC 结果。
对象“sys.sysschobjs”在 34 页中找到 2446 行。
sys.syscsrowgroups的 DBCC 结果。
对象“sys.syscsrowgroups”在 0 页中找到 0 行。
sys.sysextsources的 DBCC 结果。
对象“sys.sysextsources”在 0 页中找到 0 行。
sys.sysexttables的 DBCC 结果。
对象“sys.sysexttables”在 0 页中找到 0 行。
sys.sysextfileformats的 DBCC 结果。
对象“sys.sysextfileformats”在 0 页中找到 0 行。
sys.sysmultiobjvalues的 DBCC 结果。
对象“sys.sysmultiobjvalues”在 0 页中找到 0 行。
sys.syscolpars的 DBCC 结果。
对象“sys.syscolpars”在 18 页中找到 1047 行。
sys.sysxlgns的 DBCC 结果。
对象“sys.sysxlgns”在 0 页中找到 0 行。
sys.sysxsrvs的 DBCC 结果。
对象“sys.sysxsrvs”在 0 页中找到 0 行。
sys.sysnsobjs的 DBCC 结果。
对象“sys.sysnsobjs”在 1 页中找到 1 行。
sys.sysusermsgs的 DBCC 结果。
对象“sys.sysusermsgs”在 0 页中找到 0 行。
sys.syscerts的 DBCC 结果。
对象“sys.syscerts”在 1 页中找到 1 行。
sys.sysrmtlgns的 DBCC 结果。
对象“sys.sysrmtlgns”在 0 页中找到 0 行。
sys.syslnklgns的 DBCC 结果。
对象“sys.syslnklgns”在 0 页中找到 0 行。
sys.sysxprops的 DBCC 结果。
对象“sys.sysxprops”在 1 页中找到 1 行。
sys.sysscalartypes的 DBCC 结果。
对象“sys.sysscalartypes”在 1 页中找到 34 行。
sys.systypedsubobjs的 DBCC 结果。
对象“sys.systypedsubobjs”在 0 页中找到 0 行。
sys.sysidxstats的 DBCC 结果。
对象“sys.sysidxstats”在 5 页中找到 227 行。
sys.sysiscols的 DBCC 结果。
对象“sys.sysiscols”在 2 页中找到 433 行。
sys.sysendpts的 DBCC 结果。
对象“sys.sysendpts”在 0 页中找到 0 行。
sys.syswebmethods的 DBCC 结果。
对象“sys.syswebmethods”在 0 页中找到 0 行。
sys.sysbinobjs的 DBCC 结果。
对象“sys.sysbinobjs”在 1 页中找到 23 行。
sys.sysaudacts的 DBCC 结果。
对象“sys.sysaudacts”在 0 页中找到 0 行。
sys.sysobjvalues的 DBCC 结果。
对象“sys.sysobjvalues”在 23 页中找到 236 行。
sys.syscscolsegments的 DBCC 结果。
对象“sys.syscscolsegments”在 0 页中找到 0 行。
sys.syscsdictionaries的 DBCC 结果。
对象“sys.syscsdictionaries”在 0 页中找到 0 行。
sys.sysclsobjs的 DBCC 结果。
对象“sys.sysclsobjs”在 1 页中找到 16 行。
sys.sysrowsetrefs的 DBCC 结果。
对象“sys.sysrowsetrefs”在 0 页中找到 0 行。
sys.sysremsvcbinds的 DBCC 结果。
对象“sys.sysremsvcbinds”在 0 页中找到 0 行。
sys.sysxmitqueue的 DBCC 结果。
对象“sys.sysxmitqueue”在 0 页中找到 0 行。
sys.sysrts的 DBCC 结果。
对象“sys.sysrts”在 1 页中找到 1 行。
sys.sysconvgroup的 DBCC 结果。
对象“sys.sysconvgroup”在 0 页中找到 0 行。
sys.sysdesend的 DBCC 结果。
对象“sys.sysdesend”在 0 页中找到 0 行。
sys.sysdercv的 DBCC 结果。
对象“sys.sysdercv”在 0 页中找到 0 行。
sys.syssingleobjrefs的 DBCC 结果。
对象“sys.syssingleobjrefs”在 1 页中找到 187 行。
sys.sysmultiobjrefs的 DBCC 结果。
对象“sys.sysmultiobjrefs”在 1 页中找到 124 行。
sys.sysguidrefs的 DBCC 结果。
对象“sys.sysguidrefs”在 0 页中找到 0 行。
sys.sysfoqueues的 DBCC 结果。
对象“sys.sysfoqueues”在 0 页中找到 0 行。
sys.syschildinsts的 DBCC 结果。
对象“sys.syschildinsts”在 0 页中找到 0 行。
sys.syscompfragments的 DBCC 结果。
对象“sys.syscompfragments”在 0 页中找到 0 行。
sys.sysftsemanticsdb的 DBCC 结果。
对象“sys.sysftsemanticsdb”在 0 页中找到 0 行。
sys.sysftstops的 DBCC 结果。
对象“sys.sysftstops”在 0 页中找到 0 行。
sys.sysftproperties的 DBCC 结果。
对象“sys.sysftproperties”在 0 页中找到 0 行。
sys.sysxmitbody的 DBCC 结果。
对象“sys.sysxmitbody”在 0 页中找到 0 行。
sys.sysfos的 DBCC 结果。
对象“sys.sysfos”在 0 页中找到 0 行。
sys.sysqnames的 DBCC 结果。
对象“sys.sysqnames”在 1 页中找到 98 行。
sys.sysxmlcomponent的 DBCC 结果。
对象“sys.sysxmlcomponent”在 1 页中找到 100 行。
sys.sysxmlfacet的 DBCC 结果。
对象“sys.sysxmlfacet”在 1 页中找到 112 行。
sys.sysxmlplacement的 DBCC 结果。
对象“sys.sysxmlplacement”在 1 页中找到 19 行。
sys.sysobjkeycrypts的 DBCC 结果。
对象“sys.sysobjkeycrypts”在 1 页中找到 1 行。
sys.sysasymkeys的 DBCC 结果。
对象“sys.sysasymkeys”在 0 页中找到 0 行。
sys.syssqlguides的 DBCC 结果。
对象“sys.syssqlguides”在 0 页中找到 0 行。
sys.sysbinsubobjs的 DBCC 结果。
对象“sys.sysbinsubobjs”在 1 页中找到 3 行。
sys.syssoftobjrefs的 DBCC 结果。
对象“sys.syssoftobjrefs”在 1 页中找到 5 行。
sys.sqlagent_jobs的 DBCC 结果。
对象“sys.sqlagent_jobs”在 0 页中找到 0 行。
sys.sqlagent_jobsteps的 DBCC 结果。
对象“sys.sqlagent_jobsteps”在 0 页中找到 0 行。
sys.sqlagent_job_history的 DBCC 结果。
对象“sys.sqlagent_job_history”在 0 页中找到 0 行。
sys.sqlagent_jobsteps_logs的 DBCC 结果。
对象“sys.sqlagent_jobsteps_logs”在 0 页中找到 0 行。
sys.plan_persist_query_text的 DBCC 结果。
对象“sys.plan_persist_query_text”在 0 页中找到 0 行。
sys.plan_persist_query的 DBCC 结果。
对象“sys.plan_persist_query”在 0 页中找到 0 行。
sys.plan_persist_plan的 DBCC 结果。
对象“sys.plan_persist_plan”在 0 页中找到 0 行。
sys.plan_persist_runtime_stats的 DBCC 结果。
对象“sys.plan_persist_runtime_stats”在 0 页中找到 0 行。
sys.plan_persist_runtime_stats_interval的 DBCC 结果。
对象“sys.plan_persist_runtime_stats_interval”在 0 页中找到 0 行。
sys.plan_persist_context_settings的 DBCC 结果。
对象“sys.plan_persist_context_settings”在 0 页中找到 0 行。
sys.plan_persist_query_hints的 DBCC 结果。
对象“sys.plan_persist_query_hints”在 0 页中找到 0 行。
sys.plan_persist_query_template_parameterization的 DBCC 结果。
对象“sys.plan_persist_query_template_parameterization”在 0 页中找到 0 行。
sys.plan_persist_wait_stats的 DBCC 结果。
对象“sys.plan_persist_wait_stats”在 0 页中找到 0 行。
sys.persistent_version_store的 DBCC 结果。
对象“sys.persistent_version_store”在 0 页中找到 0 行。
sys.persistent_version_store_long_term的 DBCC 结果。
对象“sys.persistent_version_store_long_term”在 0 页中找到 0 行。
sys.wpr_bucket_table的 DBCC 结果。
对象“sys.wpr_bucket_table”在 0 页中找到 0 行。
node的 DBCC 结果。
对象“node”在 1 页中找到 1 行。
compute_node的 DBCC 结果。
对象“compute_node”在 1 页中找到 1 行。
distribution的 DBCC 结果。
对象“distribution”在 1 页中找到 8 行。
filegroup的 DBCC 结果。
对象“filegroup”在 1 页中找到 15 行。
database_file的 DBCC 结果。
对象“database_file”在 1 页中找到 22 行。
configuration_properties的 DBCC 结果。
对象“configuration_properties”在 11 页中找到 164 行。
version_history的 DBCC 结果。
对象“version_history”在 1 页中找到 1 行。
pdw_sp_configure的 DBCC 结果。
对象“pdw_sp_configure”在 1 页中找到 4 行。
sys.queue_messages_1977058079的 DBCC 结果。
对象“sys.queue_messages_1977058079”在 0 页中找到 0 行。
sys.queue_messages_2009058193的 DBCC 结果。
对象“sys.queue_messages_2009058193”在 0 页中找到 0 行。
sys.queue_messages_2041058307的 DBCC 结果。
对象“sys.queue_messages_2041058307”在 0 页中找到 0 行。
sys.filestream_tombstone_2073058421的 DBCC 结果。
对象“sys.filestream_tombstone_2073058421”在 0 页中找到 0 行。
sys.syscommittab的 DBCC 结果。
对象“sys.syscommittab”在 0 页中找到 0 行。
sys.filetable_updates_2105058535的 DBCC 结果。
对象“sys.filetable_updates_2105058535”在 0 页中找到 0 行。
CHECKDB 在数据库 'DWConfiguration' 中发现 0 个分配错误和 0 个一致性错误。
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

日常操作

可以使用 SQL management studio,点击管理,新建维护计划,“检查数据库完整性”任务。可以进行一个或者多个库的操作。

建议:业务数据库, 每周做一次完整性检查。 关注检查日志,出错要即时处理

故障修复的步骤

若数据库已经出现质疑,或者已经不完整则应该进行如下操作

--1、修改数据库为紧急模式
ALTER DATABASE AdventureWorks2012 SET EMERGENCY 
--2、更改数据库为单用户模式
ALTER DATABASE AdventureWorks2012 SET SINGLE_USER
--3、修复数据库,不允许数据丢失
DBCC CheckDB(AdventureWorks2012,REPAIR_REBUILD)
--若成功 则将数据库设置为多用户模式,再改为正常状态。若不成功 还可以找到有错误的表或者视图进行修复
dbcc CHECKTABLE(  table_name | view_name  , REPAIR_REBUILD  ) 
--若还不能成功,则可以进行允许数据库丢失的修复操作。
DBCC CheckDB(AdventureWorks2012,REPAIR_ALLOW_DATA_LOSS)
dbcc CHECKTABLE(  table_name | view_name  , REPAIR_ALLOW_DATA_LOSS  ) 
 
--修复成功 则将数据库设置为多用户模式,再改为正常状态。若不成功 还可以找到有错误的表或者视图进行修复
--4、若是可以重启的系统,可进行服务重启

由于某些数据库非常巨大,若需要加快处理速度

1、DBCC CHECKDB默认使用多线程并行检查,可以使用SP_CONFIGURE 'max degree of parallelism'来设置最大并行

2、使用WITH PHYSICAL_ONLY以较小开销检查数据库物理一致性

3、使用WITH NO_INDEX来避免检查索引

4、也可以将CHECKDB拆分成多个步骤完成,CHECKFILEGROUP CHECKALLOC CHECKTABLE

5、在进行REPAIR_ALLOW_DATA_LOSS 操作前先备份数据库。

进阶

详细看下进行修复的几个选项的区别,有助于你进行操作时候的选择。

REPAIR_ALLOW_DATA_LOSS | REPAIR_FAST | REPAIR_REBUILD 指定 DBCC CHECKDB 修复发现的错误。 仅将 REPAIR 选项作为最后手段使用。 指定的数据库必须处于单用户模式,才能使用以下修复选项之一。  

REPAIR_ALLOW_DATA_LOSS

尝试修复报告的所有错误。 这些修复可能会导致一些数据丢失,REPAIR_ALLOW_DATA_LOSS 选项是受支持的功能,但是,它可能并非总是使数据库处于物理上一致的状态的最佳选项。 如果成功,REPAIR_ALLOW_DATA_LOSS 选项可能会导致一些数据丢失。 实际上,它可能导致的数据丢失多于用户从上次已知成功备份还原数据库导致的数据丢失。 Microsoft 始终建议用户将从上次已知成功备份还原作为从由 DBCC CHECKDB 报告的错误恢复的主要方法。 REPAIR_ALLOW_DATA_LOSS 选项不是从已知成功备份还原的替代方法。 这是一个紧急选项,仅当不可从备份恢复时建议作为“最后手段”使用。

仅能使用 REPAIR_ALLOW_DATA_LOSS 选项修复的某些错误可能涉及释放行、页或一些列页以清除错误。 用户不可再访问或恢复已释放的数据,且无法确定已释放数据的准确内容。 因此,释放任何行或页后参照完整性可能不准确,因为此修复操作不包括检查或维护外键约束。 使用 REPAIR_ALLOW_DATA_LOSS 选项后,用户必须检查其数据库的参考完整性(使用 DBCC CHECKCONSTRAINTS)。

在执行修复之前,请创建属于此数据库的文件的物理副本。 这包括主数据文件 (.mdf)、任意辅助数据文件 (.ndf)、所有事务日志文件 (.ldf) 和构成数据库的其他容器,包括全文目录、文件流文件夹、内存优化数据等。 在执行修复前,请考虑将数据库的状态更改为紧急模式,并尝试从关键表中提取尽可能多的信息并保存这些数据。

REPAIR_FAST保留该语法只是为了向后兼容。 未执行修复操作。

REPAIR_REBUILD执行不会丢失数据的修复。 这包括快速修复(如修复非聚集索引中缺少的行)以及更耗时的修复(如重新生成索引)。此参数不修复涉及 FILESTREAM 数据的错误。

数据库处于紧急模式并且以 REPAIR_ALLOW_DATA_LOSS 子句运行 DBCC CHECKDB 时,将执行以下操作:

  • DBCC CHECKDB 将使用由于 I/O 或校验和错误而标记为不可访问的页,就如同这些错误没有出现过一样。 这样操作将增加从数据库恢复数据的机会。   

  • DBCC CHECKDB 将尝试使用常规的基于日志的恢复方法恢复数据库。   

  • 如果由于事务日志损坏而导致数据库恢复失败,则将重新生成事务日志。 重新生成事务日志可能导致事务一致性丢失。

另外如果做了复制的数据库,则会更麻烦

运行具有 REPAIR_ALLOW_DATA_LOSS 选项的 DBCC CHECKDB 命令可能会影响用户数据库(发布数据库和订阅数据库)以及由复制使用的分发数据库。 发布数据库和订阅数据库包括已发布的表和复制元数据表。 请注意这些数据库中的下列潜在问题:

  • 已发布的表。 可能不会复制由 CHECKDB 进程为修复损坏的用户数据而执行的操作:   

  • 合并复制使用触发器跟踪对已发布的表所做的更改。 如果 CHECKDB 进程插入、更新或删除了行,则触发器不会激发;因此,更改将不会复制。

  • 事务复制使用事务日志跟踪对已发布的表所做的更改。 然后,日志读取器代理将这些更改移动到分发数据库。 某些 DBCC 修复即使记入日志,仍然无法由日志读取器代理复制。 例如,如果数据页由 CHECKDB 进程释放,则日志读取器代理不会将它翻译为 DELETE 语句;因此,更改将不会复制。

  • 复制元数据表。 由 CHECKDB 进程为修复损坏的复制元数据表而执行的操作需要删除并重新配置复制。   

如果必须对用户数据库或分发数据库运行具有 REPAIR_ALLOW_DATA_LOSS 选项的 DBCC CHECKDB 命令:

  1. 停止系统:停止数据库和复制拓扑中所有其他数据库的活动,然后尝试同步所有节点。 有关详细信息,请参阅停止复制拓扑(复制 Transact-SQL 编程)。   

  2. 执行 DBCC CHECKDB。   

  3. 如果 DBCC CHECKDB 报表包括分发数据库中任何表或用户数据库中任何复制元数据表的修复,则请删除并重新配置复制。 有关详细信息,请参阅禁用发布和分发。   

  4. 如果 DBCC CHECKDB 报表包括任何已复制表的修复,则请执行数据验证以确定发布数据库和订阅数据库中的数据之间是否存在差异。

    后记

    数据库运维工作从来都不能偷懒,你不知道什么时候会发生什么 。 只有做足了工作,才会及早的处理好潜在的故障。 数据本来无价,只因为你付出更多,才能保证完整!

    看起来很简单的数据库完整性问题,却是有可能某天发生在你的数据库上。

猜你喜欢

转载自blog.csdn.net/capsicum29/article/details/80657963
今日推荐