2

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

从 VB.Net 调用存储过程时,它只是挂起,直到 SqlCommand 超时。从 Management Studio 调用相同的存储过程会立即执行。我的 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 以清除任何锁,重新编译存储过程,增加 SqlCommand 和 SqlConnection 超时都无济于事。

我检查了添加到参数中的数据,它是有效数据......如果我用相同的数据手动调用存储过程,它工作正常。

我最初没有使用该Using块,但更改了它以查看是否有一些资源问题没有被处理/关闭。该实用程序的内存使用量徘徊在 5MB 左右,因此似乎没有任何内存问题。

有没有人对下一步尝试解决方案有什么建议?

编辑每个评论请求添加循环和初始化代码

编辑我更新了统计信息并重建了表索引,没有变化。

编辑数据被复制到的表上有三个索引(dmDocumentField)。如果我禁用所有三个索引,那么存储过程会完美执行,尽管比索引存在时慢得多。如果我启用其中任何一个,那么该实用程序最多可以通过几百条记录,然后在 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]
4

3 回答 3

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 的真实数据类型,假定为字符串,但如果不是这种情况,则使用适当的虚拟值更改初始设置。

于 2012-06-14T19:43:36.983 回答
0

好吧,在与此作斗争之后,我手动进行了转换,因为这对于一个特定的客户来说是一次性的问题。我仍然希望我知道为什么 SqlCommand 会超时,但 SSMS 没有,但此时它已经完成了。

于 2012-06-15T20:38:09.327 回答
0

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

SELECT ID, Name FROM Table 1

然后我超时的命令是遍历 DR 记录并执行类似的操作

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

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

于 2012-11-30T00:20:28.517 回答