iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
自我挑戰組

SQL Server 基礎&調教系列 第 11

【基礎】 11.資料庫一致性

  • 分享至 

  • xImage
  •  

對抗資料庫損毀的主要防線,是定期備份,並且定期測試這些備份是否可以成功還原。

但是除此之外,SQL Server 還有提供一些工具可以用來檢查一致性的問題。

一致性錯誤

這個錯誤會導致 table、database,甚至整個 instance 變成無法存取的狀態。

還有查詢失敗、session 中斷,部分訊息會寫入 SQL Server error log。

接下來會寫幾個常見的錯誤,和發生時的解決辦法

基本上在這個時代,出現錯誤都是直接問 AI 最快。

605

發生 605 有兩種可能,取決於錯誤的嚴重性。

  1. 如果嚴重性等級是 12,則表示發生 dirty read。

    dirty read 是一種交易異常,發生在使用 Read Uncommitted isolation level,或使用 NOLOCK query hint 的時候。

    當一個交易讀到一筆實際上從未存在於 database 中的 row 時,就會發生 dirty read;原因是另一個交易後來被 rollback 了。

    要解決這個問題,可以重新執行查詢直到成功;或重寫查詢,避免使用 Read Uncommitted isolation level 或 NOLOCK query hint。

  2. 另一個更嚴重的問題,代表硬體故障。

    如果嚴重性等級是 21,則 page 可能已經損壞,或者作業系統可能提供了錯誤的 page。

    如果是這種情況,需要去備份還原,或使用 DBCC CHECKDB 來修復這個問題。

    此外,也應該要去猜 Windows administrators 和 storage team 檢查是否有可能的硬體問體。

823 Error

當 SQL Server 嘗試執行 I/O 操作時,用來執行這個動作的 Windows API 向 Database Engine 回傳錯誤時,就會發生 823 錯誤。

823 錯誤幾乎就是硬體或 driver 問題。

如果發生 823,應該使用 DBCC CHECKDB 來檢查 database 其餘部分的一致性,以及位於相同 volumn 上其他 database 的一致性。

同時要檢查儲存設備、硬碟的問題。

同時要檢查 Windows event log。

最後,有需要的話應該備份還原 database。

824 Error

如果呼叫 Windows API 成功,但是回傳的資料存在 logical consistency issues,那麼就會產生 824 錯誤。

就像 823 錯誤一樣,824 錯誤通常表示儲存系統硬體有問題。

如果產生 824 錯誤,那麼應該採取和產生 823 錯誤時相同的處理流程。

5180 Error

當系統發現一個無效的 file ID 時,就會發生 5180 錯誤。

這個錯誤通常是由 page 內部損壞的 pointer 所造成,但也可能表示 Database Engine 本身有問題。

如果遇到這個錯誤,應該從 backup 還原,或者執行 DBCC CHECKDB 來修復這個錯誤。

7105 Error

當 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 目前狀態。

Page Verify Option

這是一個 "資料庫層級” 的選項,這是用來決定 SQL Server 如何檢查 page 損毀的。

在讀取或是寫入硬碟的時候,都有可能造成 page 損毀。

Page Verify 有以下幾種設定可選

  1. CHECKSUM

    如果用這個選項,每一次 page 被寫入時,SQL Server 都會根據整個 page 建立一個 CHECKSUM 值,並將它存在 page header 中。

    CHECKSUM 值是一個 has 值,而且他在資料庫裡會是 unique。

    當 page 被讀到 buffer cache 時,SQL Server 會重新計算這個值,並與原本的值進行比較。

  2. TORN_PAGE_DETECTION

    如果用這個選項,每一次 page 被寫入時,page 中每個 512-byte sector 的前 2 byte 會被寫入 page header。

    當 page 被讀到 buffer cache 時,SQL Server 會檢查這些值,確認他們是否相同。

    這裡的缺陷很明顯 : page 完全有可能已經損毀,但因為損毀的位置不再被檢查的 bytes 之內,所以不會被發現。

    這個選項,微軟已經表明在未來版本中將不再提供,所以我們也不應該使用這個選項

  3. NONE

    如果用這個選項,那 SQL Server 就完全不會去執行 page 檢查。

CHECKSUM 是 2022 的預設選項,也是我建議使用的選項

https://ithelp.ithome.com.tw/upload/images/20260811/201185811vlmMkn07a.png

當然,CHECKSUM 會消耗一點 CPU 效能,因為他必須去計算 hash 值,但是我不認為有必要因為想要省 CPU 效能,而去把 page 驗證選項換成 NONE,因為如果 page 損毀然後沒有發現,損失的實際上比那一點 CPU 效能還要巨量很多。

微軟保留 NONE,主要是為向下相容性,以及 SQL Server 管理人員清楚明白開啟的風險,但真的沒必要開這個選項。

可疑 page

如果 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的,要記得刪掉。

實際操作

  1. 我會先建立一個 Database 叫做 TEST
  2. 建立一個 Table 叫做 CorruptTable,然後填入資料
  3. 故意把一個 page 用成損毀

非常重要

因為要故意 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 直接寫入資料頁內容

https://ithelp.ithome.com.tw/upload/images/20260811/20118581zmM7TQTL1j.pnghttps://ithelp.ithome.com.tw/upload/images/20260811/20118581mt0r89hATL.pnghttps://ithelp.ithome.com.tw/upload/images/20260811/20118581R2AnbxnPt2.pnghttps://ithelp.ithome.com.tw/upload/images/20260811/20118581BEcu8ql5OI.png

https://ithelp.ithome.com.tw/upload/images/20260811/20118581dqfqsFzoxP.pnghttps://ithelp.ithome.com.tw/upload/images/20260811/20118581LCg3kj9bXW.png

記憶體表的一致性問題

這種損毀通常發生在實體 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 層級的資訊

  1. Logins
  2. SQL Server Agent jobs
  3. Linked Servers
  4. Database 繫結
  5. …還有很多

甚至連這個 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

這個是一個工具,用來偵測損毀,也可以用來修復錯誤。

執行 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 有兩種可能

  1. 指定 TABLOCK
  2. 硬碟上沒有足夠的空間產生 snapshot
    無論是哪一種,都會導致 table 會被鎖更長的時間。

https://ithelp.ithome.com.tw/upload/images/20260811/20118581CUdbO74DU8.png
https://ithelp.ithome.com.tw/upload/images/20260811/20118581Lw1u2g9zTx.png

在真實的環境中,除非正在 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,而我們又沒有備份,所以只剩下用這個選項了,使用之前要先把資料庫切成單人模式。

https://ithelp.ithome.com.tw/upload/images/20260811/20118581wweUFYF8Vz.pnghttps://ithelp.ithome.com.tw/upload/images/20260811/20118581wCieU10znG.png
然後我們再一次去查 suspect_pages 就會看到這筆被修正的紀錄
https://ithelp.ithome.com.tw/upload/images/20260811/20118581kclLJYmqe3.png
這樣,就修復完畢。

Emergency Mode

如果今天 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 帶回來。

原因是它會嘗試強制讓交易紀錄進行復原,即使過程中遇到錯誤也會嘗試繼續。

如果這樣失敗,它會重建交易紀錄。

當然,這可能造成交易不一致,但如前面所說,這是最後手段。

實際操作

要模擬這種狀況,要先做一些事前操作。

  1. 首先,先把 Instance 關閉。
    https://ithelp.ithome.com.tw/upload/images/20260811/20118581FiryguuCM6.png
  2. 然後去把 ldf 刪掉
    https://ithelp.ithome.com.tw/upload/images/20260811/20118581JZQ95TM35v.png
  3. 再啟用 Instance 回來,然後就會看到 TEST 這個資料庫有一個提示 (復原暫止)
    https://ithelp.ithome.com.tw/upload/images/20260811/20118581tjFpuCd7uS.png
    接下來要嘗試去復原這種狀況,因為我們沒有備份檔,所以緊急模式的 DBCC CHECKDB REPAIR 是最後選項。
    https://ithelp.ithome.com.tw/upload/images/20260811/20118581uQfbJvVoB7.png
    這時候再回去看 LDF 被建立起來了,資料庫正常了。

可是會失去交易一致性,而且 restore chain 已經中斷。

因為我們已經失去交易一致性,所以現在應該執行 DBCC CHECKCONSTRAINTS,用來找出 foreign key constraints 和 check constraints 中的錯誤。

再說一次,如果在 emergency mode 下執行 DBCC CHECKDB 也失敗,那麼就沒有其他方法可以修復這個 database。

其他 DBCC

這些都比較不重要,就隨意帶過

DBCC CHECKCATALOG

在 SQL Server 中,system catalog 是一組 metadata,用來描述 database,以及 database 內部所保存的資料。

當執行 DBCC CHECKCATALOG 時,它會針對這個 catalog 執行一致性檢查。

這個 command 本來就是 DBCC CHECKDB 的一部分,但也可以單獨作為一個 command 執行。

當它單獨執行時,它接受與 DBCC CHECKDB 相同的參數,但有兩個例外:

  • PHYSICAL_ONLY
  • DATA_PURITY

這兩個參數不能用在 DBCC CHECKCATALOG

DBCC CHECKALLOC

DBCC CHECKALLOC 會針對 database 內部的 disk allocation structures 執行一致性檢查。

它本來就是 DBCC CHECKDB 的一部分,但也可以單獨作為一個 command 執行。

當它單獨執行時,它接受許多與 DBCC CHECKDB 相同的參數,但有幾個例外:

  • PHYSICAL_ONLY
  • DATA_PURITY
  • REPAIR_REBUILD

這些參數不能用在 DBCC CHECKALLOC

它的輸出會按照:

  • table
  • index
  • partition

來顯示。

DBCC CHECKTABLE

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。

這樣會讓檢查範圍出現缺口 :

  1. 跨 table 的一致性問題
  2. 損毀不一定只發生在 table

也會造成另一個問題 :

每檢查一張 table,就會產生一個新的 database snapshot,而不是建立一個 snapshot 後用來完成所有檢查。

這可能導致每一張 table 的執行時間變得更長。

DBCC CHECKFILEGROUP

DBCC CHECKFILEGROUP 會針對指定 filegroup 內的下列項目執行一致性檢查:

  • system catalog
  • allocation structures
  • tables
  • indexed views

不過,這個指令有一些限制,特別是當 table 的 indexes 儲存在不同的 filegroup 時。

在這種情境下,這些 indexes 不會被檢查一致性。

即使情況反過來也一樣:如果你正在檢查的 filegroup 裡存放的是 indexes,但對應的 base table 存放在另一個 filegroup,那麼一致性檢查也會受到限制。


如果你有一張 partitioned table,而且它分散儲存在多個 filegroups,DBCC CHECKFILEGROUP 只會檢查儲存在「被指定檢查的 filegroup」上的 partition 或 partitions 的一致性。

DBCC CHECKFILEGROUP 的參數和 DBCC CHECKDB 相同,但有幾個例外:

  • DATA_PURITY 不能用
  • 不能指定任何 repair options
  • 還需要指定 filegroup name 或 filegroup ID

也就是說,DBCC CHECKFILEGROUP 適合用來檢查某個 filegroup 範圍內的資料結構,但它不能完整取代 DBCC CHECKDB

DBCC CHECKIDENT

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 抑制資訊性訊息,不讓它們顯示在結果中。

https://ithelp.ithome.com.tw/upload/images/20260811/20118581H4akee7wPn.png
https://ithelp.ithome.com.tw/upload/images/20260811/20118581Dsl7ijK1a5.png

在執行 DBCC CHECKDB,或其他用來修復損毀的 DBCC commands 之後,建議再執行 DBCC CHECKCONSTRAINTS

原因是 DBCC commands 的 repair options 不會把 constraint integrity 納入考量。

VLDBs 的一致性檢查

如果是 VLDBs,可能很難找到足夠長的維護時段來執行 DBCC CHECKDB,而且如果在正式環境中,還會造成效能問題。

如果是大量較小的 database,但是他們有共同的 IFRA,例如 SAN 或私有雲,也可能遇到類似問題。

但是,確保 database 保持一致性,還是應該是 DBA 工作清單中非常高優先級的事項。

所以應該要在當下的環境中找到一種策略,同時達成維護需求與效能目標。

接下來我會建議幾種策略。

DBCC CHECKDB with PHYSICAL_ONLY

我們可以採用一種策略是 :

定期執行 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

但是這個有幾個缺點

  1. 你要很有錢,因為你要買次要伺服器,阿她平常沒事就在那放著,只是為了執行一致性檢查。

  2. 如果今天搬到次要伺服器上,發現有損毀,你還要去判斷這是正式環境上就損毀? 還是複製備份還原到次要伺服器上才損毀的?

    代表如果發現錯誤,還是得回到正式伺服器上去執行 DBCC CHECKDB

但是優點就是,這不會給正式環境造成負擔。

日常檢查 SOP

小型資料庫

  1. 每天低峰時段執行
DBCC CHECKDB(N'資料庫名稱') WITH PHYSICAL_ONLY, NO_INFOMSGS;
  1. 每周找時間執行一次
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;
  1. 處理那個可疑 page,處理方法很多種備份還原也行、DBCC CHECKDB REPAIR 也行,但最好還配合查一下為什麼會有可疑 page。

我突然發現可以貼 SQL 語法了?? 那我前面那麼辛苦截圖語法是為了什麼

大型資料庫

  1. 一樣每天先做基礎檢查
DBCC CHECKDB(N'資料庫名稱') WITH PHYSICAL_ONLY, NO_INFOMSGS;
  1. 每月一次完整 CHECKDB
DBCC CHECKDB(N'資料庫名稱') WITH NO_INFOMSGS;
  1. 分天跑 DBCC CHECKFILEGROUP
DBCC CHECKFILEGROUP(N'資料庫名稱') WITH NO_INFOMSGS;
  1. 如果是 SAN,那就把第三點改成 DBCC CHECKDB,然後一樣分組去跑。

每月再做一次

  1. 還原 full backup
  2. 還原 differential backup
  3. 還原 log backups
  4. 執行 DBCC CHECKDB
  5. 確認應用程式關鍵資料可查

CHECKDB 失敗時

  1. 先不要修
  2. 保存錯誤訊息
  3. 查 suspect_pages
  4. 查 SQL Server Error Log
  5. 確認是否有硬體、儲存、I/O 錯誤
  6. 找最近的乾淨備份
  7. 優先 restore 或 page restore
  8. 沒有備份才考慮 DBCC repair
  9. repair 後執行 DBCC CHECKCONSTRAINTS
  10. 重新做 full backup

上一篇
【基礎】 10.統計資訊
下一篇
【基礎】 12.安全性 Model
系列文
SQL Server 基礎&調教19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言