我使用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,TaskCompletionSource1 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,TaskCompletionSource1 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;
答案 0 :(得分:1)
它已超时,因为您的批量加载需要一个多小时才能完成。根据{{3}},超时设置指的是
操作在超时前完成的秒数。
25GB文件加载到数据库可能需要一个多小时才有意义,那么为什么不尝试设置更高的超时值以便有足够的时间来完成呢?