對抗資料庫損毀的主要防線,是定期備份,並且定期測試這些備份是否可以成功還原。
但是除此之外,SQL Server 還有提供一些工具可以用來檢查一致性的問題。
這個錯誤會導致 table、database,甚至整個 instance 變成無法存取的狀態。
還有查詢失敗、session 中斷,部分訊息會寫入 SQL Server error log。
接下來會寫幾個常見的錯誤,和發生時的解決辦法
基本上在這個時代,出現錯誤都是直接問 AI 最快。
發生 605 有兩種可能,取決於錯誤的嚴重性。
如果嚴重性等級是 12,則表示發生 dirty read。
dirty read 是一種交易異常,發生在使用 Read Uncommitted isolation level,或使用 NOLOCK query hint 的時候。
當一個交易讀到一筆實際上從未存在於 database 中的 row 時,就會發生 dirty read;原因是另一個交易後來被 rollback 了。
要解決這個問題,可以重新執行查詢直到成功;或重寫查詢,避免使用 Read Uncommitted isolation level 或 NOLOCK query hint。
另一個更嚴重的問題,代表硬體故障。
如果嚴重性等級是 21,則 page 可能已經損壞,或者作業系統可能提供了錯誤的 page。
如果是這種情況,需要去備份還原,或使用 DBCC CHECKDB 來修復這個問題。
此外,也應該要去猜 Windows administrators 和 storage team 檢查是否有可能的硬體問體。
當 SQL Server 嘗試執行 I/O 操作時,用來執行這個動作的 Windows API 向 Database Engine 回傳錯誤時,就會發生 823 錯誤。
823 錯誤幾乎就是硬體或 driver 問題。
如果發生 823,應該使用 DBCC CHECKDB 來檢查 database 其餘部分的一致性,以及位於相同 volumn 上其他 database 的一致性。
同時要檢查儲存設備、硬碟的問題。
同時要檢查 Windows event log。
最後,有需要的話應該備份還原 database。
如果呼叫 Windows API 成功,但是回傳的資料存在 logical consistency issues,那麼就會產生 824 錯誤。
就像 823 錯誤一樣,824 錯誤通常表示儲存系統硬體有問題。
如果產生 824 錯誤,那麼應該採取和產生 823 錯誤時相同的處理流程。
當系統發現一個無效的 file ID 時,就會發生 5180 錯誤。
這個錯誤通常是由 page 內部損壞的 pointer 所造成,但也可能表示 Database Engine 本身有問題。
如果遇到這個錯誤,應該從 backup 還原,或者執行 DBCC CHECKDB 來修復這個錯誤。
當 table 中的某個 row 參照到一個不存在的 LOB(Large Object Block)structure 時,就會發生 7105 錯誤。
這可能是因為 dirty read 所造成,情況與 605 severity 12 error 類似;也可能是因為 page 損毀所造成。
損毀可能發生在指向 LOB structure 的 data page 中,也可能發生在 LOB structure 本身的 page 中。
如果遇到 7105 錯誤,應該執行 DBCC CHECKDB 來檢查錯誤。
如果沒有找到任何錯誤,那麼這個錯誤很可能是 dirty read 的結果。
但如果有找到錯誤,就應該從 backup 還原 database,或者使用 DBCC CHECKDB 來修復問題。
SQL Server 提供了一些機制,用來在 page 從 disk 讀取,以及寫入 disk 時,驗證 page 的完整性。
它也提供了一份 corrupt pages 的記錄,協助我們識別已發生的錯誤類型、錯誤發生了多少次,以及已經損毀的 page 目前狀態。
這是一個 "資料庫層級” 的選項,這是用來決定 SQL Server 如何檢查 page 損毀的。
在讀取或是寫入硬碟的時候,都有可能造成 page 損毀。
Page Verify 有以下幾種設定可選
CHECKSUM
如果用這個選項,每一次 page 被寫入時,SQL Server 都會根據整個 page 建立一個 CHECKSUM 值,並將它存在 page header 中。
CHECKSUM 值是一個 has 值,而且他在資料庫裡會是 unique。
當 page 被讀到 buffer cache 時,SQL Server 會重新計算這個值,並與原本的值進行比較。
TORN_PAGE_DETECTION
如果用這個選項,每一次 page 被寫入時,page 中每個 512-byte sector 的前 2 byte 會被寫入 page header。
當 page 被讀到 buffer cache 時,SQL Server 會檢查這些值,確認他們是否相同。
這裡的缺陷很明顯 : page 完全有可能已經損毀,但因為損毀的位置不再被檢查的 bytes 之內,所以不會被發現。
這個選項,微軟已經表明在未來版本中將不再提供,所以我們也不應該使用這個選項
NONE
如果用這個選項,那 SQL Server 就完全不會去執行 page 檢查。
CHECKSUM 是 2022 的預設選項,也是我建議使用的選項

當然,CHECKSUM 會消耗一點 CPU 效能,因為他必須去計算 hash 值,
但是我不認為有必要因為想要省 CPU 效能,而去把 page 驗證選項換成 NONE,因為如果 page 損毀然後沒有發現,損失的實際上比那一點 CPU 效能還要巨量很多。
微軟保留 NONE,主要是為向下相容性,以及 SQL Server 管理人員清楚明白開啟的風險,但真的沒必要開這個選項。
如果 SQL Server 發現某個 page 有錯誤的 checksum,那麼它會把這些 page 記錄在 MSDB database 中一個名為 dbo.suspect_pages 的 table 裡。
它也會把任何遇到 823 或 824 錯誤的 page 記錄在這個 table 中。
這個 table 包含六個 columns
| Column | Description |
|---|---|
| Database_id | 包含 suspect page 的 database ID |
| File_id | 包含 suspect page 的 file ID |
| Page_id | 被判定為 suspect 的 page ID |
| Event_Type | 導致 suspect_pages 被更新的事件性質 |
| Error_count | 遞增計數器,用來記錄該事件已發生的次數 |
| Last_updated_date | 該 row 最後一次被更新的時間 |
其中 Event_Type 會是以下這幾種
| Event_type | Description |
|---|---|
| 1 | 823 或 824 error |
| 2 | Bad checksum |
| 3 | Torn page |
| 4 | Restored |
| 5 | Repaired |
| 7 | 由 DBCC CHECKDB deallocated |
只要對不上 checksum 的,他就會寫進這張 table,然後如果有做 DBCC CHECKDB 或是 有 backup 還原過,他就會去更新 Event_type,把它改成標記 4或5,代表有處理過。
平常時候,應該要去監控這個 table,注意有沒有 page 損毀的資訊。
另外注意,這張 table 微軟在設計的時候,有限制她最多就是只能 1000 筆資料,所以有處理過的、type 是 4或5的,要記得刪掉。
非常重要因為要故意 page 損毀,所以我會用到 DBCC WRITEPAGE 這個東西 這個東西非常危險,所以不要在正式環境使用,絕對不要在正式環境裡用。
在範例中,我會執行一個
DBCC WRITEPAGE(7, 1, 176, 2000, 1, 0x61, 1);
類似這種東西,這個是直接去 file 裡面,指定 offset 位置,寫入一個 byte 資料。
用這種方式去損毀 page。
這是直接修改 page,不透過 insert、update 等方式,你不小心在正式環境中做了又不小心沒切到測試用的 database,你的頭就會很痛,所以絕對不要在正式環境做。
| 參數 | 值 | 意思 |
|---|---|---|
| database_id | 7 | 要修改哪個 database |
| file_id | 1 | 要修改哪個 database file |
| page_id | 176 | 要修改哪個 page |
| offset | 2000 | 從 page 內第幾個 byte 位置開始寫 |
| length | 1 | 寫入幾個 bytes |
| data | 0x61 | 寫入的資料,0x61 是十六進位,代表字元 a |
| directORbufferpool | 1 | 直接寫入資料頁內容 |






這種損毀通常發生在實體 I/O 上,所以有些人會理所當然認為記憶體表不會有這種問題,但這是錯的。
雖然 memory-optimized tables 常駐在 memory 中,但是 tables 的副本,以及根據你的 durability settings,可能還包含你的 data 的副本,會被保存在 physical files 中。這是為了確保在 SQL Server instance 重新啟動之後,tables 和 data 仍然可以使用。
在前面記憶體表相關的地方有提到過。
然而就是這些 files 仍然可能發生損毀。
此外,資料也可能因為 faulty RAM chip 之類的問題,在記憶體中發生損毀。
可是,DBCC CHECKDB 的修復選項不支援記憶體表
不過呢,如果你去對記憶體 filegroup 的 database 進行備份,SQL Server 會對這個 filegroup 內的 files 執行 checksum validation。
因此,非常重要的是:不只要定期做 backup,也要定期確認這些 backup 可以成功 restore 。
因為當記憶體表發生損毀的時候,唯一的選項,就是備份還原。
如果 Master database 發生損毀, 那SQL Server instance 會無法啟動
如果發生這種狀況,就需要重建 system database,然後從 backups 還原最新的備份。
有關備份策略會專門開一篇備份來講,但這裡凸顯一件事,備份系統資料庫是很重要的。
如果今天遇到這種問題,但是又沒有備份可以還原,那就會遺失所有 instance 層級的資訊
甚至連這個 instance 裡有哪些 user databases 的資訊也會遺失,因此你需要重新 attach 這些 databases。
如果要重建系統資料庫,需要執行 setup
在安裝的時候,我就有說過,setup 那個安裝檔要留下,就是為了現在這種狀況要去處理,如果原本檔案不見了,那要去找對應你當前版本一模一樣的安裝檔,找不到的話,一樣頭會很痛。
以下是 setup 的參數跟power shell 指令
| Parameter | Description |
|---|---|
/ACTION |
指定 action parameter 為 Rebuilddatabase。 |
/INSTANCENAME |
指定包含 corrupt system database 的 instance name。 |
/Q |
這個 parameter 代表 quiet。使用這個參數可以在沒有任何使用者互動的情況下執行 setup。 |
/SQLCOLLATION |
這是一個 optional parameter,可用來指定 instance 的 collation。如果省略,則會使用 Windows OS 的 collation。 |
/SAPWD |
如果你的 instance 使用 mixed-mode authentication,則使用這個 parameter 指定 sa account 的 password。 |
/SQLSYSADMINACCOUNTS |
使用這個 parameter 指定哪些 accounts 應該被設定為這個 instance 的 sysadmins。 |
$SetupPath = "你的安裝檔案路徑\setup.exe"
$InstanceName = "你的 instance 名稱"
$SqlServiceName = "MSSQL`$$InstanceName"
$SqlAgentServiceName = "SQLAgent`$$InstanceName"
$CurrentUser = (whoami)
$SaPassword = "你的 sa密碼"
if (!(Test-Path $SetupPath)) {
throw "找不到 setup.exe:$SetupPath"
}
Stop-Service -Name $SqlAgentServiceName -Force -ErrorAction SilentlyContinue
Stop-Service -Name $SqlServiceName -Force -ErrorAction SilentlyContinue
& $SetupPath `
/QUIET `
/ACTION=REBUILDDATABASE `
/INSTANCENAME=$InstanceName `
/SQLSYSADMINACCOUNTS="$CurrentUser" `
/SAPWD="$SaPassword"
Write-Host "Setup Exit Code = $LASTEXITCODE"
$LogRoot = "C:\Program Files\Microsoft SQL Server\170\Setup Bootstrap\Log"
$LatestLog = Get-ChildItem $LogRoot |
Sort-Object LastWriteTime -Descending |
Select-Object -First 1
notepad "$($LatestLog.FullName)\Summary.txt"
成功重新安裝的話就會看到,所有 DATABASE 全部卸離、Login 資訊全部清空了
然後再去把database 掛起來就可以了
這時候可以去注意到,再去看一次我們在偵測一致性錯誤 / 可疑page 時候做的故意損壞 page 那邊,如果現在再去看一次那個 msdb.dbo.suspect_pages 他會是空的,但是再去 SELECT 一次 TEST 資料庫的話,錯誤紀錄就又會出來了,等等會修復這個我們故意製造出來的損壞。
這個是一個工具,用來偵測損毀,也可以用來修復錯誤。
執行 DBCC CHECKDB 的時候,預設情況下,會建立一個 database snapshot,然後針對這個 snapshot 執行一致性檢查。
snapshot 目的是取得一個交易狀態一致的時間點,可以避免檢查過程中受到尚未完成的交易或資料變動影響,同時降低對原始資料庫的鎖定與競爭。我會有一篇專門寫這東西。
DBCC CHECKDB 也可以平行檢查多個物件來提升效能,實際效果取決於 CPU 核心數,還有該 Instanct 的 MAXDOP 設定。
執行 DBCC CHECKDB,目的只是為了偵測資料庫損毀沒有要修復的時候,可以指定一些參數。
| Argument | Description |
|---|---|
NOINDEX |
指定只對 heap 與 clustered index 結構執行完整性檢查,但不檢查 nonclustered indexes。 |
EXTENDED_LOGICAL_CHECKS |
強制執行 XML indexes、indexed views、spatial indexes 的邏輯一致性檢查。 |
NO_INFOMSGS |
防止結果中回傳資訊性訊息。當你正在尋找問題時,這可以減少雜訊,因為只會回傳錯誤,以及 severity level 大於 10 的警告。 |
TABLOCK |
DBCC CHECKDB 預設會建立 database snapshot,並針對該 snapshot 執行一致性檢查,以避免在 database 中取得 locks,造成資源競爭。指定這個選項會改變這個行為:SQL Server 不會建立 snapshot,而是先在 database 上取得 temporary exclusive lock,接著在它正在檢查的結構上取得 exclusive locks。在高寫入負載的情況下,這可以縮短 DBCC CHECKDB 的執行時間,但代價是會和其他正在執行的程序產生資源競爭。它也會導致 system table metadata validation 與 service broker validation 被跳過。 |
ESTIMATEONLY |
指定此參數時,不會執行任何檢查。它只會根據其他指定的參數,計算執行檢查時所需要的 TempDB 空間。 |
PHYSICAL_ONLY |
使用此參數時,DBCC CHECKDB 只會執行 database allocation consistency checks、system catalogs consistency checks,以及驗證 database 中每個 page 的完整性。這個選項不能和 DATA_PURITY 一起使用。 |
DATA_PURITY |
指定執行 column integrity checks,例如確認值是否落在該 data type 的合法範圍內。這個參數適用於從 SQL Server 2000 或更早版本升級而來的 database。對於較新的 database,或已經用 DATA_PURITY 掃描過的 SQL Server 2000 database,這類檢查預設就會執行。 |
ALL_ERRORMSGS |
僅為了向後相容性而保留。對 SQL Server 2022 database 沒有影響。 |
DBCC CHECKDB 是一個非常消耗資源的程序,會消耗大量 CPU 跟 I/O。
因此,建議在維護時段執行它,以避免造成應用程式效能問題。
Database Engine 會根據 instance 層級的 MAXDOP 設定,以及程序開始時伺服器的負載量,自動決定要分配多少 CPU cores 給 DBCC CHECKDB 使用。
不過,如果預期在 DBCC CHECKDB 執行期間,伺服器負載會增加,那麼可以開啟 Trace Flag 2528,將這個程序限制為只使用單一 CPU core。
執行 DBCC CHECKDB 後沒有產生 snapshot 有兩種可能
無論是哪一種,都會導致 table 會被鎖更長的時間。


在真實的環境中,除非正在 troubleshooting 某個特定錯誤,否則通常不會手動執行 DBCC CHECKDB。
通常會用 Agent 處理或是維護排程。
DBCC CHECKDB 如果有錯誤,會導致排成失敗,排成失敗再去通知管理員。
有關排程的東西會再找一篇寫。
現在要開始修復一開始我們故意製造出來的損毀。
用 DBCC CHECKDB 修復的時候有兩種選項可以選
REPAIR_REBUILD
這個當然是比較建議使用的選項。它可以用來解決不會造成資料遺失的問題,例如錯誤的 page pointers,或 nonclustered index 內部的損毀。
REPAIR_ALLOW_DATA_LOSS
會嘗試修復它遇到的所有錯誤,但是就像它的名稱所暗示的,這可能會造成資料遺失。
只有在沒有備份可以用的時候,才應該使用 REPAIR_ALLOW_DATA_LOSS 這個選項來還原。
在使用 DBCC CHECKDB + REPAIR 選項之前,永遠永遠都應該要先執行不帶任何 REPAIR 選項去執行一次 DBCC CHECKDB。
因為DBCC CHECKDB 會告訴你這些錯誤的最低修復選項是什麼,反正意思就是 REPAIR 是 DBCC CHECKDB 的最後手段。
在前面這個案例中,如果去執行修復選項 REPAIR_REBUILD 是不夠的,SQL Server 會跟我說最低修復等級是 REPAIR_ALLOW_DATA_LOSS,而我們又沒有備份,所以只剩下用這個選項了,使用之前要先把資料庫切成單人模式。


然後我們再一次去查 suspect_pages 就會看到這筆被修正的紀錄
這樣,就修復完畢。
如果今天 database files 損壞到 database 已經無法存取、無法復原,甚至使用 REPAIR_ALLOW_DATA_LOSS 選項也無法修復,而且也沒有可用的備份,那最後手段就是在緊急模式下,執行 DBCC CHECKDB,然後使用 REPAIR_ALLOW_DATA_LOSS 選項。
emergency mode 是修復 database 的最後手段。如果在這個模式下仍然無法存取 database,那麼你也無法透過任何其他方式存取它。
當 database 處於 emergency mode 時執行這個動作,DBCC CHECKDB 會嘗試復原資料;對於因 損毀而無法存取的 pages,它會把這些 pages 當成沒有錯誤來處理,藉此嘗試把資料救回來。
這個操作也可以把因交易紀錄損毀而無法存取的 database 帶回來。
原因是它會嘗試強制讓交易紀錄進行復原,即使過程中遇到錯誤也會嘗試繼續。
如果這樣失敗,它會重建交易紀錄。
當然,這可能造成交易不一致,但如前面所說,這是最後手段。
要模擬這種狀況,要先做一些事前操作。


可是會失去交易一致性,而且 restore chain 已經中斷。
因為我們已經失去交易一致性,所以現在應該執行 DBCC CHECKCONSTRAINTS,用來找出 foreign key constraints 和 check constraints 中的錯誤。
再說一次,如果在 emergency mode 下執行 DBCC CHECKDB 也失敗,那麼就沒有其他方法可以修復這個 database。
這些都比較不重要,就隨意帶過
在 SQL Server 中,system catalog 是一組 metadata,用來描述 database,以及 database 內部所保存的資料。
當執行 DBCC CHECKCATALOG 時,它會針對這個 catalog 執行一致性檢查。
這個 command 本來就是 DBCC CHECKDB 的一部分,但也可以單獨作為一個 command 執行。
當它單獨執行時,它接受與 DBCC CHECKDB 相同的參數,但有兩個例外:
PHYSICAL_ONLY
DATA_PURITY
這兩個參數不能用在 DBCC CHECKCATALOG。
DBCC CHECKALLOC 會針對 database 內部的 disk allocation structures 執行一致性檢查。
它本來就是 DBCC CHECKDB 的一部分,但也可以單獨作為一個 command 執行。
當它單獨執行時,它接受許多與 DBCC CHECKDB 相同的參數,但有幾個例外:
PHYSICAL_ONLY
DATA_PURITY
REPAIR_REBUILD
這些參數不能用在 DBCC CHECKALLOC。
它的輸出會按照:
來顯示。
DBCC CHECKTABLE 會作為 DBCC CHECKDB 的一部分,針對 database 中的每一個 table 和 indexed view 執行。
不過,它也可以單獨作為一個 command 執行,用來檢查某一張特定 table,以及該 table 的 indexes。
它會針對指定 table 執行一致性檢查。
如果有任何 indexed views 參照到這張 table,它也會執行跨 table 的一致性檢查。
它接受與 DBCC CHECKDB 相同的參數,但使用 DBCC CHECKTABLE 時,還需要指定要檢查的 table name 或 table ID。
這功能看起來很好用
我看過有人把他們公司的 TABLE 分成兩組,然後不執行 DBCC CHECKDB,改成每天輪流對其中一半 TABLES 去執行 DBCC CHECKTABLE。
這樣會讓檢查範圍出現缺口 :
也會造成另一個問題 :
每檢查一張 table,就會產生一個新的 database snapshot,而不是建立一個 snapshot 後用來完成所有檢查。
這可能導致每一張 table 的執行時間變得更長。
DBCC CHECKFILEGROUP 會針對指定 filegroup 內的下列項目執行一致性檢查:
不過,這個指令有一些限制,特別是當 table 的 indexes 儲存在不同的 filegroup 時。
在這種情境下,這些 indexes 不會被檢查一致性。
即使情況反過來也一樣:如果你正在檢查的 filegroup 裡存放的是 indexes,但對應的 base table 存放在另一個 filegroup,那麼一致性檢查也會受到限制。
如果你有一張 partitioned table,而且它分散儲存在多個 filegroups,DBCC CHECKFILEGROUP 只會檢查儲存在「被指定檢查的 filegroup」上的 partition 或 partitions 的一致性。
DBCC CHECKFILEGROUP 的參數和 DBCC CHECKDB 相同,但有幾個例外:
DATA_PURITY 不能用也就是說,DBCC CHECKFILEGROUP 適合用來檢查某個 filegroup 範圍內的資料結構,但它不能完整取代 DBCC CHECKDB。
DBCC CHECKIDENT 會掃描指定 table 中的所有 rows,找出 IDENTITY column 裡的最高值。
接著,它會檢查儲存在 table metadata 中的下一個 IDENTITY value,確認這個值是否大於 table 中 IDENTITY column 的最高值。
| Argument | Description |
|---|---|
Table Name |
要檢查的 table 名稱。 |
NORESEED |
回傳 IDENTITY column 的最大值,以及目前的 IDENTITY value,但即使需要修正,也不會重新設定該 column 的 seed。 |
RESEED |
將目前的 IDENTITY value 重新設定為 table 中最大的 IDENTITY value。 |
New Reseed Value |
搭配 RESEED 使用,用來指定新的 IDENTITY seed value。這個選項要謹慎使用,因為如果把 IDENTITY value 設得比 table 中目前最大值還低,而且 IDENTITY column 上有 primary key 或 unique constraint,就可能產生錯誤。 |
WITH NO_INFOMSGS |
抑制資訊性訊息,不讓它們顯示在結果中。 |
DBCC CHECKCONSTRAINTS這個是在眾多不重要之中相對重要的 DBCC
DBCC CHECKCONSTRAINTS 可以檢查 table 中特定 foreign key 或 check constraint 的完整性,也可以檢查單一 table 上的所有 constraints,或檢查 database 中所有 tables 的所有 constraints
| Argument | Description |
|---|---|
Table or Constraint |
指定要檢查的 constraint 名稱或 ID;或者指定 table 名稱或 ID,以檢查該 table 上所有已啟用的 constraints。如果省略這個參數,則會檢查 database 中所有 tables 上所有已啟用的 constraints。 |
ALL_CONSTRAINTS |
如果 DBCC CHECKCONSTRAINTS 是針對整張 table 或整個 database 執行,這個選項會強制一起檢查 disabled constraints,而不只檢查 enabled constraints。 |
ALL_ERRORMSGS |
預設情況下,如果 DBCC CHECKCONSTRAINTS 找到違反 constraint 的 rows,只會回傳前 200 筆。指定 ALL_ERRORMSGS 後,會回傳所有違反 constraint 的 rows,即使數量超過 200。 |
NO_INFOMSGS |
抑制資訊性訊息,不讓它們顯示在結果中。 |


在執行 DBCC CHECKDB,或其他用來修復損毀的 DBCC commands 之後,建議再執行 DBCC CHECKCONSTRAINTS。
原因是 DBCC commands 的 repair options 不會把 constraint integrity 納入考量。
如果是 VLDBs,可能很難找到足夠長的維護時段來執行 DBCC CHECKDB,而且如果在正式環境中,還會造成效能問題。
如果是大量較小的 database,但是他們有共同的 IFRA,例如 SAN 或私有雲,也可能遇到類似問題。
但是,確保 database 保持一致性,還是應該是 DBA 工作清單中非常高優先級的事項。
所以應該要在當下的環境中找到一種策略,同時達成維護需求與效能目標。
接下來我會建議幾種策略。
我們可以採用一種策略是 :
定期執行 DBCC CHECKDB,理想情況是每天相對離峰的時段,並搭配 PHYSICAL_ONLY 選項。
然後再用週期性但較低頻率的方式,執行完整的 consistency check,理想情況下每週一次。
當我們使用 PHYSICAL_ONLY 選項執行 DBCC CHECKDB 時,SQL Server 會對 system catalogs 和 allocation structures 執行一致性檢查,並掃描與驗證每一張 table 的每一個 page。
這樣做的結果是:由 I/O errors 造成的 corruption 可以被捕捉到。
但是其他問題,例如 logical consistency errors,不會被識別出來。
這就是為什麼仍然需要每週執行一次完整掃描。
另一種適用於 VLDB 的策略,是把 DBCC CHECKDB 的工作負載分散到多個離峰時段執行。
例如,如果你的 VLDB 有多個 filegroups,那麼可以在星期一、三、五,對其中一半的 filegroups 執行 DBCC CHECKFILEGROUP;星期二、四、六,對另一半的 filegroups 執行 DBCC CHECKFILEGROUP。
然後保留星期日,執行一次完整的 DBCC CHECKDB。
仍然建議每週完整執行一次 DBCC CHECKDB,因為 DBCC CHECKFILEGROUP 不會執行某些檢查,例如驗證 Service Broker objects。
如果是以下這種架構或是 SAN、私有雲也可以這樣做
SQL Server A
DB_A 300 GB
DB_B 500 GB
SQL Server B
DB_C 400 GB
DB_D 700 GB
SQL Server C
DB_E 200 GB
DB_F 600 GB
只是跟 filegroups 不同的是,不要單純的把 db 隨機 5050 去分,要看他容量讓兩組平均一點。
在實務上,遇到這種有多個 DB 在多 instance 的狀況,通常會使用 CMS 來管理。
CMS 是中央管理伺服器,在這裡他本身也是一個 SQL Server instance
結構大概像下面那樣
CMS
├── Production
│ ├── SQLPROD01
│ ├── SQLPROD02
│ ├── SQLPROD03
│
├── Reporting
│ ├── SQLRPT01
│ ├── SQLRPT02
│
└── Development
│ ├── SQLDEV01
│ ├── SQLDEV02
CMS 裡面可以去存各種 instance、db 的 metadata。
然後再藉由 PowerShell 去跟這些執行個體互動,以達到方便管理的效果。
降低正式環境因為執行 DBCC CHECKDB 而產生負載的最後一種策略,是把這項工作卸載到次要伺服器上。
如果決定採用這個方法,就需要先對 VLDB 做一次 full backup,然後將它還原到次要伺服器上,然後在次要伺服器上執行 DBCC CHECKDB。
但是這個有幾個缺點
你要很有錢,因為你要買次要伺服器,阿她平常沒事就在那放著,只是為了執行一致性檢查。
如果今天搬到次要伺服器上,發現有損毀,你還要去判斷這是正式環境上就損毀? 還是複製備份還原到次要伺服器上才損毀的?
代表如果發現錯誤,還是得回到正式伺服器上去執行 DBCC CHECKDB
但是優點就是,這不會給正式環境造成負擔。
DBCC CHECKDB(N'資料庫名稱') WITH PHYSICAL_ONLY, NO_INFOMSGS;
DBCC CHECKDB(N'資料庫名稱') WITH NO_INFOMSGS;
3.沒有失敗就很棒不用處理,如果 CHECKDB 失敗,先查可疑 page
SELECT
DB_NAME(sp.database_id) AS [資料庫名稱],
mf.name AS [檔案名稱],
sp.page_id AS [Page ID],
CASE sp.event_type
WHEN 1 THEN N'823 或 824 錯誤,或 Torn Page'
WHEN 2 THEN N'Bad Checksum'
WHEN 3 THEN N'Torn Page'
WHEN 4 THEN N'已從備份還原'
WHEN 5 THEN N'已由 DBCC 修復'
WHEN 7 THEN N'已由 DBCC CHECKDB 釋放配置'
ELSE N'未知事件類型'
END AS [事件類型],
sp.error_count AS [錯誤發生次數],
sp.last_update_date AS [最後更新時間]
FROM msdb.dbo.suspect_pages sp
INNER JOIN sys.master_files mf
ON sp.database_id = mf.database_id
AND sp.file_id = mf.file_id;
我突然發現可以貼 SQL 語法了?? 那我前面那麼辛苦截圖語法是為了什麼
DBCC CHECKDB(N'資料庫名稱') WITH PHYSICAL_ONLY, NO_INFOMSGS;
DBCC CHECKDB(N'資料庫名稱') WITH NO_INFOMSGS;
DBCC CHECKFILEGROUP(N'資料庫名稱') WITH NO_INFOMSGS;
每月再做一次
CHECKDB 失敗時