SQL Server 2008 R2 是否總是因某些大文本操作而出現嚴重級別 20 錯誤?
當我們在 SQL Server 2008 R2 實例上執行它時,每次都會導致嚴重性 20 錯誤。它在我們的 SQL Server 2016 實例上沒有這個問題。
詢問:
DECLARE @v varchar(MAX) = REPLICATE(CONVERT(varchar(max),'a'),524289); SELECT @v = @v FROM(SELECT 1 AS a) AS b;
結果:
Location: tmpilb.cpp:3256 Expression: fNoReaderWriterConflict SPID: 90 Process ID: 1576 Location: tmpilb.cpp:3306 Expression: fNoReaderWriterConflict SPID: 90 Process ID: 1576 Msg 3624, Level 20, State 1, Line 4 A system assertion check has failed. Check the SQL Server error log for details. Typically, an assertion failure is caused by a software bug or data corruption. To check for database corruption, consider running DBCC CHECKDB. If you agreed to send dumps to Microsoft during setup, a mini dump will be sent to Microsoft. An update might be available from Microsoft in the latest Service Pack or in a QFE from Technical Support. Msg 0, Level 20, State 0, Line 0 A severe error occurred on the current command. The results, if any, should be discarded.
SELECT @@VERSION
:Microsoft SQL Server 2008 R2 (SP3) - 10.50.6000.34 (X64) Aug 19 2014 12:21:34 Copyright (c) Microsoft Corporation Standard Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) (Hypervisor)
SQLDump0002.txt(來自非生產伺服器):
Computer type is Intel(R) Xeon(R) CPU E5430 @ 2.66GHz. Bios Version is DELL - 1 Phoenix ROM BIOS PLUS Version 1.10 2.5.0 8 X64 level 8664, 2 Mhz processor (s). Windows NT 6.1 Build 7601 CSD Service Pack 1. Memory MemoryLoad = 87% Total Physical = 32762 MB Available Physical = 4058 MB Total Page File = 65524 MB Available Page File = 27332 MB Total Virtual = 8388607 MB Available Virtual = 8355194 MB **Dump thread - spid = 0, EC = 0x00000003EF7E5F00
這是此版本 SQL Server 2008 R2 中的錯誤嗎?
更新:
- 這確實會產生一組與故障轉儲相關的文件。它們的外行可讀部分基本上重複了上面的錯誤結果。
- 我們認識到 SQL Server 2008 R2 已經過時並且不再受支持。我們將進行升級。
- 我們已經通過在 SELECT 語句之外設置大文本變數來解決這個問題。
- 我們很好奇這是否發生在任何其他環境中,我們希望將其公開記錄以防發生在其他人身上。
這在 Microsoft SQL Server 2008 R2 (SP2) build 10.50.4000 上為我重現。它似乎在 SP3 之後的一段時間內得到了修復。該問題已在 Connect 上報告(隨後遷移到使用者語音,以便該連結有效)。
LOB 中需要超過 512KB 的數據,以及從同一個變數中讀取的變數賦值,而無需執行任何計算。
例如:
-- No error at 512KB DECLARE @v varchar(max) = REPLICATE(CONVERT(varchar(max), 'a'), 512 * 1024); SET @v = (SELECT @v); -- Assertion failure at 512KB + 1 DECLARE @v varchar(max) = REPLICATE(CONVERT(varchar(max), 'a'), 512 * 1024 + 1); SET @v = (SELECT @v);
該語句幾乎沒有錯誤地執行。SQL Server 正確執行所有計算,甚至毫無問題地將@v 分配給@v。斷言發生在 SQL Server 關閉語句時,將@v 的最終值寫回到提供的變數引用@v。就像@v 是賦值語句的參數一樣。如果這聽起來很複雜,那是因為它是。變數賦值有點小技巧,有一些奇怪的遺留行為。我不羨慕那些必須維護該程式碼的所有怪癖。
CInMemIlb
由於 SQL Server 使用記憶體中的 ILockBytes (ILB) 類來處理操作,因此斷言不會發生在 512KB 或以下的值上。您可能已經註意到斷言消息 (tmpilb.cpp) 中的 ILB。超過 512KB,SQL ServerCMainIlb
改為使用,它在寫入時使用 blob 句柄檢查其他讀取器。將@v 分配給自身而不進行修改意味著此檢查失敗。在許多可能的解決方法中,自然不屬於上述觀察的兩個是:
- 分配給不同的變數
- 執行計算
範例如下所示。兩者都不會產生錯誤的斷言:
-- Assign to a different variable DECLARE @v varchar(max) = REPLICATE(CONVERT(varchar(max), 'a'), 512 * 1024 + 1); DECLARE @v2 varchar(max); SET @v2 = (SELECT @v); -- Perform a calculation DECLARE @v varchar(max) = REPLICATE(CONVERT(varchar(max), 'a'), 512 * 1024 + 1); SET @v = (SELECT @v + '');
有趣的是,最近在 SQL Server 2019 對查詢儲存和 polybase 的修復中再次出現了相同的斷言。