Azure - SqlBulkCopy 引发超时过期异常

Posted

技术标签:

【中文标题】Azure - SqlBulkCopy 引发超时过期异常【英文标题】:Azure - SqlBulkCopy throwing a timeout expired exception 【发布时间】:2016-10-07 19:02:44 【问题描述】:

我在 vm 上使用 azure sql 数据库 (v12)。我有两个不同的数据库实例——一个用于暂存,一个用于生产。我正在尝试从暂存中获取数据并通过单击按钮将其插入生产中。此代码“有时”成功运行,这意味着它会随机成功。否则我会收到以下错误:

BULK COPY 提交异常类型:0System.Data.SqlClient.SqlException BULK COPY 消息:0超时。在操作完成之前超时时间已过或服务器没有响应。尝试连接到路由目标时发生此故障。尝试连接到原始服务器所花费的持续时间是 - [Pre-Login] 初始化 = 1;握手=17; [登录] 初始化=0;身份验证=0; [登录后] 完成=0;

这是我用来完成这项任务的代码,也许有一个我没有看到的缺陷。通过转储 StringBuilder,我可以看到 SELECT 查询有效,DELETE 查询有效,但是当我尝试使用 SqlBulkCopy 复制数据时抛出错误。任何帮助将不胜感激。我已经浏览了一堆 MSDN 文档,但没有运气 -> 添加更长的 CommandTimeouts,添加更长的 BulkCopyTimeout,并在我的防火墙上重新配置端口。还是没有运气。

我使用过的资源:@​​987654321@

https://azure.microsoft.com/nb-no/documentation/articles/sql-database-develop-direct-route-ports-adonet-v12/

Timeout expired with SqlBulkCopy

public static object SyncData()

    StringBuilder sb = new StringBuilder();
    sb.AppendLine("Internal Connection...");
    string internalConnectionString = GetConnectionString("ConnectionString");
    using (SqlConnection internalConnection = new SqlConnection(internalConnectionString))
    
        internalConnection.Open();              
        SqlCommand selectCommand = internalConnection.CreateCommand();
        selectCommand.CommandTimeout = 180;
        try
        
            selectCommand.CommandText = "SELECT * FROM dbo.test";
            SqlDataReader reader = selectCommand.ExecuteReader();

            sb.AppendLine("External Connection...");
            string externalConnectionString = GetConnectionString("ExternalConnectionString");
            using (SqlConnection externalConnection = new SqlConnection(externalConnectionString))
            
                externalConnection.Open();              
                SqlCommand CRUDCommand = externalConnection.CreateCommand();
                CRUDCommand.CommandTimeout = 180;
                SqlTransaction transaction = externalConnection.BeginTransaction("test");
                CRUDCommand.Connection = externalConnection;
                CRUDCommand.Transaction = transaction;
                try
                
                    CRUDCommand.CommandText = "DELETE FROM dbo.test";
                    sb.AppendLine("DELETE: Number of rows affected = " + CRUDCommand.ExecuteNonQuery());
                    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(externalConnection, SqlBulkCopyOptions.KeepIdentity, transaction))
                    
                        try
                        
                            bulkCopy.DestinationTableName = "dbo.test";
                            bulkCopy.BatchSize = 100;
                            bulkCopy.BulkCopyTimeout = 180;
                            bulkCopy.WriteToServer(reader);

                            sb.AppendLine("Table data copied successfully");

                            transaction.Commit();
                            sb.AppendLine("Transaction committed.");
                        
                        catch (Exception ex)
                        
                            sb.AppendLine("BULK COPY Commit Exception Type: 0" + ex.GetType());
                            sb.AppendLine("  BULK COPY Message: 0" + ex.Message);
                            try
                            
                                transaction.Rollback();
                            
                            catch (Exception ex2)
                            
                                sb.AppendLine("Rollback Exception Type: 0" + ex2.GetType());
                                sb.AppendLine("  Message: 0" + ex2.Message);
                            
                        
                        finally
                        
                            reader.Close();
                        
                    
                
                catch (Exception ex)
                
                    sb.AppendLine("Commit Exception Type: 0" + ex.GetType());
                    sb.AppendLine("  Message: 0" + ex.Message);

                    try
                    
                        transaction.Rollback();
                    
                    catch (Exception ex2)
                    
                        sb.AppendLine("Rollback Exception Type: 0" + ex2.GetType());
                        sb.AppendLine("  Message: 0" + ex2.Message);
                    
                
            
        
        catch (Exception ex)
        
            sb.AppendLine("Commit Exception Type: 0" + ex.GetType());
            sb.AppendLine("  Message: 0" + ex.Message);
        
    
    return sb.ToString();

【问题讨论】:

两台服务器是否在同一个虚拟网络上?您是否尝试过尝试超时并可能增加批量大小以减少往返次数?虽然我使用 Dapper、Reactive Extensions 和 Simple.Data 来完成相同的事情,但我有一个类似的过程。在我的情况下,我只需要调整设置,直到找到最佳结果。我也有重试逻辑,但没有灵丹妙药恕我直言。 是的,两个数据库都在同一个 Azure 服务器上。我尝试将超时时间增加到 30 分钟,但这只会让它们挂起 30 分钟......我现在正在复制的表只有 400 行,所以改变批量大小对我没有影响。 进程是否在同一个虚拟网络上运行代码? 【参考方案1】:

在创建 SqlBulkCopy 实例时,您将传递连接字符串 externalConnectionString,从而打开一个新连接。这可能会导致两个连接尝试修改同一个表时出现死锁问题。

您是否尝试将现有连接 externalConnection 传递给 SqlBulkCopy 构造函数而不是连接字符串?

【讨论】:

好主意,我试试看。 你说得对,当我实例化 SqlBulkCopy 时,由于我之前对同一张表的 DELETE 查询,我锁定了该表。我所要做的就是将构造函数更改为using (SqlBulkCopy bulkCopy = new SqlBulkCopy(externalConnection, SqlBulkCopyOptions.KeepIdentity, transaction)),它运行良好。谢谢!

以上是关于Azure - SqlBulkCopy 引发超时过期异常的主要内容,如果未能解决你的问题,请参考以下文章

SqlBulkCopy Azure DataTable 比流式传输更快

Azure 服务总线 PeekLock 在五秒后超时

接口调用过于频繁会引发超时错误吗

Cordova geolocation.getCurrentPosition 在 iPad 上引发超时

SQL Server 2008 R2 的可重试 SQLBulkCopy

上传到 Azure 存储时出现内部 500 错误