SQL Server: 內部錯誤。提供給讀取資料行值的緩衝區太小。(zh-TW)
前陣子用了 SQL Server 2005 中極少人使用的 Query Notification 功能,且我下的 SQL 指令明明就很單純,只是做一個簡單的 SELECT 查詢卻會引來 SQL Server 的內部錯誤,自己奮戰了一個多月無解,最後還是靠微軟的技術支援中心幫我解了這個難題。
如果你安裝的是中文版的 SQL Server 2005 的話訊息的話,那麼訊息就一定會只有中文,我想全世界只有我這篇文章是中文且可參考的資料,查這些資料真是累死我了,早知道就早點打電話尋求支援。
同一種錯誤,我從各方取得各種不同的錯誤訊息如下:
Event Log 得到的錯誤:
內部錯誤。提供給讀取資料行值的緩衝區太小。請執行 DBCC CHECKDB,以檢查是否有任何損毀。
將錯誤訊息嘗試翻譯成英文關鍵字才能找到相關資料,完整的英文訊息如下:
Internal error. Buffer provided to read column value is too small. Run DBCC CHECKDB to check for any corruption."
從 InnerException 得到的錯誤:
嚴重錯誤 682 發生於 06 22 2009 5:28PM。請記錄錯誤和時間,並連絡您的系統管理員。
英文錯誤訊息為:
Warning: Fatal error 682 occurred at Feb 8 2007 11:49AM. Note the error and time, and contact your system administrator
透過 SQL Server Profiler 得到的錯誤:
Error: 682, Severity: 22, State: 148
因為且這個錯誤訊息是直接從 SQL Server 傳出來的,所以我直覺的研判是 SQL Server 的 Bug,也確實有查到這個與這個錯誤,不過早在 Service Pack 2 就修復了,目前 SQL Server 2005 出到 Service Pack 3,建議開發人員要隨時升級到最新版,避免無謂的時間浪費。如果你的資料庫真的出問題,可以參考這篇文章來救你。
最後,我發現問題出現在我宣告 SqlCommand 的寫法造成了這個錯誤:
view plaincopy to clipboardprint?
- foreach (System.Data.Common.DbParameter dbp in dc.GetCommand(q).Parameters)
- {
- cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
- }
foreach (System.Data.Common.DbParameter dbp in dc.GetCommand(q).Parameters)
{
cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
}
最後修正成以下程式碼才解決這個問題:
view plaincopy to clipboardprint?
- foreach (System.Data.Common.DbParameter dbp in dc.GetCommand(q).Parameters)
- {
- if (dbp.DbType == System.Data.DbType.AnsiString
- || dbp.DbType == System.Data.DbType.String)
- {
- SqlParameter pa = new SqlParameter();
- pa.DbType = dbp.DbType;
- pa.ParameterName = dbp.ParameterName;
- pa.Value = dbp.Value;
- pa.Size = 2000; // 這裡是非常非常重要的關鍵!
- cmd.Parameters.Add(pa);
- }
- else
- {
- cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
- }
- }
foreach (System.Data.Common.DbParameter dbp in dc.GetCommand(q).Parameters)
{
if (dbp.DbType == System.Data.DbType.AnsiString
|| dbp.DbType == System.Data.DbType.String)
{
SqlParameter pa = new SqlParameter();
pa.DbType = dbp.DbType;
pa.ParameterName = dbp.ParameterName;
pa.Value = dbp.Value;
pa.Size = 2000; // 這裡是非常非常重要的關鍵!
cmd.Parameters.Add(pa);
}
else
{
cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
}
}
原理說明(以我個人的理解來說,可能並非原本的SQL SERVER 的設計邏輯)
使用 SqlCacheDependency 必須先準備 SqlCommand 物件,所有 SqlCommand 中傳入的參數會變成快取資料表(暫存資料表)的索引欄位,而這些參數會綁定(Binding)該欄位的長度,以確保欄位不會變動。
當 SqlCommand 物件中的 SqlParameter 參數沒有明確指定長度時,預設就會是第一筆回傳值的長度,不過當該欄位屬「變動長度」的欄位時,就可能會發生「第一筆資料欄位長度是 8 個字元,但第二筆的資料長度是 9 個字元」的情況,以導致出現「提供給讀取資料行值的緩衝區太小」的問題。
相關連結
- FIX: Error message when you run a query that references a temporary table in SQL Server 2005: "Internal error. Buffer provided to read column value is too small. Run DBCC CHECKDB to check for any corruption"
- 如何識別 SQL Server 的版本
- Internal error. Buffer provided to read column value is too small. Run DBCC CHECKDB to check for any corruption
- 下載詳細資料: SQL Server 2005 SP3
- 嚴重錯誤 682 發生於 06 22 2009 5:28PM。請記錄錯誤和時間,並連絡您的系統管理員。
- 使用查詢通知 (SQL Server 2008 線上叢書)
- 啟用查詢通知 (ADO.NET)
- ASP.NET 應用程式中的 SqlDependency (ADO.NET)
- 使用 SqlDependency 來偵測變更 (ADO.NET)
[ 本文同步刊載於 http://blog.miniasp.com/post/2009/07/Internal-error-Buffer-provided-to-read-column-value-is-too-small.aspx ]