2012-06-14 70 views
2

我有一個轉換實用程序,基本上從一個表複製值到另一個。它工作了一段時間,但我遇到了一個客戶的奇怪問題。他們用公用程序獲得了150萬條記錄,但現在它完全停止了。SqlCommand調用SQL Server存儲過程超時

從VB.Net調用存儲過程時,它只是掛起,直到SqlCommand超時。從Management Studio調用相同的存儲過程即刻執行。對於SqlCommand的我VB.Net代碼如下(insertConn定義和之前打開,dr是已在前面的步驟填充了從完全不同的SqlConnection和SqlCommand的情況下,一個SqlDataReader):

Dim conn As New SqlConnection("connection string here") 
Dim insertConn As New SqlConnection("connection string here") 
Dim dr As SqlDataReader = Nothing 
Dim readCommand As New SqlCommand("my query here", conn) 
conn.Open() 
insertConn.Open() 
... 
dr = readCommand.ExecuteReader() 
... 
While dr.Read() 
    Using insertCommand = New SqlCommand("dmDocumentFieldInsert", insertConn) 
     insertCommand.CommandType = CommandType.StoredProcedure 

     insertCommand.Parameters.AddWithValue("@DocumentKey", dr("DocumentKey")) 
     insertCommand.Parameters.AddWithValue("@FieldId", "TITLE") 
     insertCommand.Parameters.AddWithValue("@FieldValue", dr("DocumentTitle")) 
     insertCommand.ExecuteNonQuery() 
    End Using 
End While 

我試着重新啓動SQL Server以清除所有鎖,重新編譯sproc,增加SqlCommand和SqlConnection超時全部無濟於事。

我檢查了要添加到參數中的數據,它是有效的數據...如果我手動調用具有相同數據的sproc,它可以正常工作。

我原本沒有使用Using塊,但改變了這個看看是否有一些資源問題沒有被處置/關閉。該實用程序的內存使用量僅在5MB左右,所以看起來沒有任何內存問題。

有沒有人對下一步嘗試解決方案有什麼建議?根據註釋

編輯新增循環和初始化代碼請求

編輯我最新統計資料和重建表索引,沒有任何變化。

編輯表中有三個索引將數據複製到(dmDocumentField)。如果我禁用了所有三個索引,那麼該sproc就會完美執行,儘管比索引存在時慢得多。如果我啓用它們中的任何一個,那麼該實用程序最多可以通過幾百條記錄,然後在sproc上同時超時。刪除並重新創建索引不起作用。表的結構和指標如下:

CREATE TABLE [dbo].[dmDocumentField](
[FieldKey] [bigint] IDENTITY(1,1) NOT NULL, 
[DocumentKey] [char](36) NOT NULL, 
[FieldId] [varchar](10) NOT NULL, 
[FieldValue] [varchar](255) NOT NULL, 
CONSTRAINT [PK_dmDocumentField] PRIMARY KEY NONCLUSTERED 
(
[FieldKey] ASC, 
[DocumentKey] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

索引(除了PK):

CREATE NONCLUSTERED INDEX [dmDocumentField_DocumentKey] ON [dbo].[dmDocumentField] 
(
[DocumentKey] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 

CREATE NONCLUSTERED INDEX [dmDocumentField_DocumentKey_IFieldId_IFieldValue] ON [dbo].[dmDocumentField] 
(
[DocumentKey] ASC 
) 
INCLUDE ( [FieldId], 
[FieldValue]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
+0

我還應該提到,該實用程序是在VB.Net 4中,所討論的SQL Server是SQL Server 2008 R2 Standard。 – Kettch19

+1

SQL探查器中的任何異常? –

+0

您可以嘗試使用[Enterprise Library](http://msdn.microsoft.com/zh-cn/library/ff648951.aspx)中的數據訪問方法。 –

回答

0

那麼,在戰鬥之後,我又做了一些手工轉換,因爲這是一個特定客戶的一次性問題。我仍然希望我知道爲什麼SqlCommand會超時,但SSMS沒有,但是現在已經完成了。

1

我會試試這個:

... 
dr = readCommand.ExecuteReader() 
... 
insertCommand = New SqlCommand("dmDocumentFieldInsert", insertConn) 
insertCommand.CommandType = CommandType.StoredProcedure 
insertCommand.Parameters.AddWithValue("@DocumentKey", string.Empty)) 
insertCommand.Parameters.AddWithValue("@FieldId", "TITLE") 
insertCommand.Parameters.AddWithValue("@FieldValue", string.Empty)) 

Dim tr As SqlTransaction 
tr = insertConn.BeginTransaction 
insertCommand.Transaction = tr 
While dr.Read() 
     insertCommand.Parameters("@DocumentKey").Value = dr("DocumentKey") 
     insertCommand.Parameters("@FieldValue").Value = dr("DocumentTitle") 
     insertCommand.ExecuteNonQuery() 
End While 

tr.Commit() 

這可能將是較少的內存密集型(創建命令,創建參數內環路repetead),150萬記錄的可能是不同。
注意我不知道@DocumentKey和@FieldValue的真實數據類型,假定是字符串,但如果不是這種情況,請使用適當的虛擬值更改初始設置。

+0

好點,我沒有提到所有三個參數都是字符串。更具體地說,DocumentKey是char(36),FieldId是varchar(10),FieldValue是varchar(255)。 – Kettch19

+0

此外,我最初的代碼非常接近您的建議,但在排除故障的熱度中嘗試了另一種方式。我只是將它改回到你的建議,但結果沒有改變。 :( – Kettch19

+0

[這篇文章](http://msdn.microsoft.com/en-us/magazine/ee236412.aspx)非常有趣。您的VARCHAR類型的列而不是NVARCHAR?在文章中有強烈的建議由UNICODE轉換而產生的問題 – Steve

0

您的命令是否對您的DataReader選擇的同一個表執行操作?我也有類似的情況,這讓我做這樣的事情在執行上的讀卡器

SELECT ID, Name FROM Table 1 

,然後我的命令是超時通過DR記錄是循環和做這樣的事情

UPDATE Table1 SET Name = 'foo' WHERE ID = 1 

當我將我的SELECT更改爲使用DataTable進行存儲,而不是DataReader,它立即工作,就像在SSMS中一樣。