﻿# SQL Server: 內部錯誤。提供給讀取資料行值的緩衝區太小。

前陣子用了 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，也確實有查到[這個](https://web.archive.org/web/20150228182510/http://support.microsoft.com:80/kb/938697)與[這個](https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=124755)錯誤，不過早在 Service Pack 2 就修復了，目前 SQL Server 2005 出到 [Service Pack 3](http://web.archive.org/web/20100131113253/http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&FamilyID=ae7387c3-348c-4faa-8ae5-949fdfbe59c4)，建議開發人員要隨時升級到最新版，避免無謂的時間浪費。如果你的資料庫真的出問題，可以參考[這篇文章](http://social.msdn.microsoft.com/Forums/zh-TW/240/thread/4fa8ccaa-1fb8-4886-88ee-8adf916d7ceb)來救你。

最後，我發現問題出現在我宣告 SqlCommand 的寫法造成了這個錯誤：

```csharp
foreach (System.Data.Common.DbParameter dbp in dc.GetCommand(q).Parameters)
{
    cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
}
```

最後修正成以下程式碼才解決這個問題：

```csharp
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 個字元」的情況，以導致出現「**提供給讀取資料行值的緩衝區太小**」的問題。

### 後記

即便如此，我覺得 SQL Server 應該要能處理這種情況，這種判斷不應該在 AP 層做才對，不知道微軟會不會聽到我的心聲？還是我的觀念有誤？

不過我最近還真是「幸運」，讓我學了這麼多鬼東西。 = =''

**相關連結**

-   [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"](https://web.archive.org/web/20150228182510/http://support.microsoft.com:80/kb/938697)
-   [如何識別 SQL Server 的版本](http://support.microsoft.com/default.aspx/kb/321185/zh-tw)
-   [Internal error. Buffer provided to read column value is too small. Run DBCC CHECKDB to check for any corruption](https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=124755)
-   [下載詳細資料： SQL Server 2005 SP3](http://web.archive.org/web/20100131113253/http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&FamilyID=ae7387c3-348c-4faa-8ae5-949fdfbe59c4)
-   [嚴重錯誤 682 發生於 06 22 2009 5:28PM。請記錄錯誤和時間，並連絡您的系統管理員。](http://social.msdn.microsoft.com/Forums/zh-TW/240/thread/f53b0fc0-7e5c-4f0f-9879-dfc0ee44caa7)
-   [使用查詢通知](http://msdn.microsoft.com/zh-tw/library/ms175110.aspx) (SQL Server 2008 線上叢書)
-   [啟用查詢通知 (ADO.NET)](http://msdn.microsoft.com/zh-tw/library/ms172133.aspx)
-   [ASP.NET 應用程式中的 SqlDependency (ADO.NET)](http://msdn.microsoft.com/zh-tw/library/9dz445ks.aspx)
-   [使用 SqlDependency 來偵測變更 (ADO.NET)](http://msdn.microsoft.com/zh-tw/library/62xk7953.aspx)
