我有一个转换实用程序,它基本上将值从一个表复制到另一个表。它有一段时间很有效,但我遇到了一个客户的奇怪问题。他们通过该实用程序获得了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]
答案 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中一样。