2012-06-14 50 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中一样。