Could not continue scan with NOLOCK due to data movement


在產品環境中定時執行SP時,偶爾會遇到SP執行失敗的情況,SQL Server拋出的錯誤消息是:

Could not continue scan with NOLOCK due to data movement

 從錯誤消息的字面意思上來理解,存儲過程執行失敗的原因,很有可能是:SQL Server正在對基礎表進行全表掃描,表帶有NOLOCK鎖提示,在掃描的當前位置缺少一個或多個數據頁。但是,缺失的數據頁並不能說明數據庫中存在損壞問題,此錯誤的根本原因是由於DML語句引起的頁面拆分導致頁面被刪除或移動,在某一個時刻,數據庫無法保證數據的一致性,導致SQL Server無法繼續掃描操作。為了驗證是否是數據頁導致的,可以使用CHECKDB命令:

DBCC CHECKDB(MY_DATABASE) WITH PHYSICAL_ONLY

如果數據庫出現故障,或者數據出現丟失,該命令會顯示出詳細的錯誤信息。

但是,通常情況下,出現數據庫故障的情況非常少,因此,該命令通常不會返回任何錯誤消息。排除掉數據庫故障這個錯誤之外,那么出現這種錯誤的原因,只有一個可能,那就是在堆表上執行SELECT命令的時候,使用了表提示(hint) with(nolock),同時有一個update命令在更新該表,增加了表中字段長度,使得某一個或某幾個數據頁被拆分。由於帶with(nolock)的select 查詢不會申請任何鎖,不會阻塞X鎖的執行,這使得update操作和select操作可以同時執行。

要解決該問題,最簡單的方案是把with(nolock) hint去掉,讓select 操作阻塞update操作的執行,也就是說,在查詢表的時候,不能更新表,就可以避免該問題的再次發生。

該問題發生的條件,我認為是以下三個條件共同作用的結果:

  • 該表是一個堆表,且數據量較大,行寬較大,包含LOB類型的數據列
  • 對堆表同時執行查詢操作和更新操作,並且查詢操作帶有with(nolock) hint
  • 查詢操作是一個Join操作,並且連接操作(很可能是哈希join)持續的時間較長

 

DBCC CHECKDB是什么?

DBCC CHECKDB 的作用是檢查數據庫中所有對象的邏輯和物理完整性,這個命令實際上調用多個命令來完成完整性檢查:

  • 運行DBCC CHECKALLOC 檢查數據庫中硬盤空間分配結構的一致性
  • 運行DBCC CHECKTABLE 檢查構成表或索引視圖的所有頁面和結構的完整性。
  • 運行 DBCC CHECKCATALOG 檢查catalog的一致性
  • 驗證數據庫中每個索引視圖的內容的有效性
  • 對於使用FILESTREAM,當把varbinary(max)數據存儲再文件系統中時,驗證表的元數據和文件系統(目錄和文件)之間鏈接的一致性。

DBCC CHECKDB命令的語法是:

DBCC CHECKDB [ ( database_name | database_id | 0 [ , NOINDEX | , Repair ]  ) ]    
    [ WITH      
            [ ALL_ERRORMSGS ]    
            [ , EXTENDED_LOGICAL_CHECKS ]     
            [ , NO_INFOMSGS ]    
            [ , TABLOCK ]    
            [ , ESTIMATEONLY ]    
            [ , { PHYSICAL_ONLY | DATA_PURITY } ]    
            [ , MAXDOP  = number_of_processors ]      
    ]    

參數注釋:

database_name | database_id | 0: 指定執行完整性檢查的數據庫,如果不指定該參數,默認值是當前的數據庫

NOINDEX:指定不對用戶表的非聚集索引進行密集檢查,這有助於減少命令整體執行的時間, NOINDEX不會影響系統表,因為始終對系統表索引執行完整性檢查。

Repair:用於指定命令如何修復發現的錯誤,僅在萬不得已時才使用REPAIR選項,指定的數據庫必須處於單用戶模式下才能使用修復選項,修復選項有三個有效值:

  • REPAIR_ALLOW_DATA_LOSS:嘗試修復所有的錯誤,但是可能導致數據丟失
  • REPAIR_REBUILD:執行無丟失數據的修復,此選項無法修復跟FILESTREAM 數據相關的錯誤。
  • REPAIR_FAST:僅僅是向后兼容,不做任何修復

ALL_ERRORMSGS:顯示素有的錯誤消息,這是默認的設置

EXTENDED_LOGICAL_CHECKS:對索引視圖、XML索引、空間索引執行邏輯一致性檢查

NO_INFOMSGS:不顯示信息性消息

TABLOCK:使命令執行時對基礎表上表級鎖,這使得命令執行的更快,但是會降低數據庫的並發性。

ESTIMATEONLY:用於顯示運行DBCC CHECKDB所需的tempdb空間消耗的估計數量,這數量是估計的,不做實際的數據庫檢查。

PHYSICAL_ONLY:將檢查范圍限制在頁面和記錄頭部(Record Header)的物理結構的完整性,以及數據庫空間分配的一致性上,該選項用於使用相對少的開銷對數據庫物理一致性的檢查。

DATA_PURITY:指定檢查列值的范圍,列值完整性檢查默認情況下處於啟用狀態,並且不需要DATA_PURITY選項。如果指定了PHYSICAL_ONLY選項,那么不會執行列完整性的檢查。

MAXDOP:執行命令運行的最大並發程度

 

 

參考文檔:

DBCC CHECKDB (Transact-SQL)

Error 601: Could not continue scan with NOLOCK due to SQL Server data movement


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM