如何调试,SQL Server异常,在操作完成之前经过的超时时间或服务器没有响应

时间:2014-12-31 12:35:01

标签: sql sql-server sqlbulkcopy

我使用SqlBulkCopy将一个大文件(约25 GB,4亿行)加载到SQL Server 2014中。

我的批量副本大小为10k行,超时为1小时。整个文件在一个事务中,因为我想存储整个文件或在发生故障时回滚。我在这个表上有3个索引(一个唯一的聚簇索引,另外两个是非聚簇索引)。

有时我会遇到这个例外:

  

System.Data.SqlClient.SqlException(0x80131904):超时已过期。操作完成之前经过的超时时间或服务器没有响应。

     

System.ComponentModel.Win32Exception(0x80004005):等待操作超时

     

at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception,Boolean breakConnection,Action 1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error) at System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync() at System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket() at System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer() at System.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlBulkCopy.RunParser(BulkCopySimpleResultSet bulkCopyHandler) at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinuedOnSuccess(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource 1 source)          在System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsyncContinued(BulkCopySimpleResultSet internalResults,String updateBulkCommandText,CancellationToken cts,TaskCompletionSource 1 source) at System.Data.SqlClient.SqlBulkCopy.CopyBatchesAsync(BulkCopySimpleResultSet internalResults, String updateBulkCommandText, CancellationToken cts, TaskCompletionSource 1 source)          在System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet internalResults,CancellationToken cts,TaskCompletionSource 1 source) at System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletionSource 1 source)          在System.Data.SqlClient.SqlBulkCopy.WriteToServerInternalAsync(CancellationToken ctoken)          在System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServerAsync(Int32 columnCount,CancellationToken ctoken)          在System.Data.SqlClient.SqlBulkCopy.WriteToServer(IDataReader reader)

如果发生异常,我会回滚整个事务,但在尝试回滚时我又看到了一个例外。我不明白为什么SqlTransaction不处于可用状态,因为我的代码没有在其他任何地方关闭连接/事务。

  

System.InvalidOperationException:此SqlTransaction已完成;它不再可用了。

我已经在某种程度上进行了调试,在SSMS中我看到有一个开放的交易

select @@TRANCOUNT  ==> this gives "0" (I didn't understand why)

dbcc opentran ==> this gives me a open transaction

Oldest active transaction:
    SPID (server process ID): 58
    UID (user ID) : -1
    Name          : user_transaction
    LSN           : (159:2843368:1)
    Start time    : Dec 30 2014 11:20:13:903PM
    SID           : 0x0105000000000005150000005d28f57fd53ad8354354e02ae9881a00
DBCC execution completed. If DBCC printed error messages, contact your system administrator.

然后使用这个SQL脚本,我发现它被卡在了一行

insert bulk dbo.#mytablename#

状态为running,timestamp与抛出异常的时间完全匹配 - 1小时(批量复制超时)。但我无法弄清楚为什么SQL Server会被困在这里以及为什么需要花费更多时间。有没有办法进一步调试?

SELECT 
   r.[session_id],
   c.[client_net_address],
   s.[host_name],
   c.[connect_time],
   [request_start_time] = s.[last_request_start_time],
   [current_time] = CURRENT_TIMESTAMP,
   r.[percent_complete],
   [estimated_finish_time] = DATEADD
       (
           MILLISECOND,
           r.[estimated_completion_time], 
           CURRENT_TIMESTAMP
       ),
   current_command = SUBSTRING
       (
           t.[text],
           r.[statement_start_offset]/2,
           COALESCE(NULLIF(r.[statement_end_offset], -1)/2, 2147483647)
       ),
   module = COALESCE(QUOTENAME(OBJECT_SCHEMA_NAME(t.[objectid], t.[dbid])) 
       + '.' + QUOTENAME(OBJECT_NAME(t.[objectid], t.[dbid])), '<ad hoc>'),
   [status] = UPPER(s.[status])
 FROM
     sys.dm_exec_connections AS c
 INNER JOIN
     sys.dm_exec_sessions AS s
     ON c.session_id = s.session_id
 LEFT OUTER JOIN
     sys.dm_exec_requests AS r
     ON r.[session_id] = s.[session_id]
 OUTER APPLY
     sys.dm_exec_sql_text(r.[sql_handle]) AS t
 WHERE
     c.session_id = 58;

1 个答案:

答案 0 :(得分:1)

它已超时,因为您的批量加载需要一个多小时才能完成。根据{{​​3}},超时设置指的是

  

操作在超时前完成的秒数。

25GB文件加载到数据库可能需要一个多小时才有意义,那么为什么不尝试设置更高的超时值以便有足够的时间来完成呢?