调用SQL Server存储过程的SqlCommand超时

时间:2012-06-14 19:21:54

标签: vb.net stored-procedures sqlcommand

我有一个转换实用程序,它基本上将值从一个表复制到另一个表。它有一段时间很有效,但我遇到了一个客户的奇怪问题。他们通过该实用程序获得了150万条记录,但现在它完全停止了。

从VB.Net调用存储过程时,它会挂起,直到SqlCommand超时。从Management Studio调用相同的sproc会立即执行。我的SqlCommand的VB.Net代码如下(insertConn已定义并在之前打开,dr是一个SqlDataReader,它已在前一步中从完全不同的SqlConnection和SqlCommand实例中填充):

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]

3 个答案:

答案 0 :(得分: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()

这可能会减少内存密集度(创建命令,在循环内重复创建参数),并且150万条记录可能会有所不同。
注意我不知道@DocumentKey和@FieldValue的实际数据类型,假设是字符串,但如果不是这样,那么用适当的虚拟值更改初始设置。

答案 1 :(得分:0)

嗯,经过多次斗争之后我手工完成了转换,因为对于一个特定的客户来说这是一次性的问题。我仍然希望我知道为什么SqlCommand超时,但SSMS没有,但它已经完成了。

答案 2 :(得分:0)

您的命令是否对DataReader选择的同一个表执行操作?我有类似的情况,我正在做一些像执行读者

的事情
SELECT ID, Name FROM Table 1

然后我的超时命令是循环DR记录并执行类似

的操作
UPDATE Table1 SET Name = 'foo' WHERE ID = 1

当我更改SELECT以使用DataTable进行存储而不是DataReader时,它立即起作用,就像在SSMS中一样。