無可奈何花落去,數據丟失時時來;何當共談完整性,卻話巴山夜雨時----詳解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 報表包括任何已複製表的修復,則請執行數據驗證以確定發佈數據庫和訂閱數據庫中的數據之間是否存在差異。

    後記

    數據庫運維工作從來都不能偷懶,你不知道什麼時候會發生什麼 。 只有做足了工作,纔會及早的處理好潛在的故障。 數據本來無價,只因爲你付出更多,才能保證完整!

    看起來很簡單的數據庫完整性問題,卻是有可能某天發生在你的數據庫上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章