禁用超时时 SqlBulkCopy 到 Azure 超时

SqlBulkCopy to Azure Timing out when Timeouts are disabled

我正在尝试使用 .NET Core 中的 SqlBulkCopy 将几百万行批量插入开发实例 Azure SQL 数据库。

我已禁用连接字符串超时和 BulkCopyTimeout(将它们都设置为 0),但我仍然超时。

现在这不是一台高级机器(它是一个开发环境),而且这个过程很容易使 DTU 达到最大值……但我对 DTU 最大值应该如何工作的理解是它是节流机制,而不是中止机制。无限超时,我希望这个过程需要一段时间,但最终会完成。相反,我看到的是过程开始......上传一堆行......然后在奇怪的时间超时:2:38,4:20......没有韵律或原因。

这让我认为这是某种传输错误,但我显然遇到了 TimeoutException。

根据 Bulk insert is not working properly in Azure SQL Server 中的建议,我也尝试将批次设置得非常小,但这似乎也无济于事。

谁能解释这里发生了什么,以及如何解决它?这阻碍了高可见度项目的开发,我不想告诉人们我可以让它在笔记本电脑的 SQL Server Express 上运行,但不能在 Azure DB 上运行。

请 运行 以下查询,让我们尝试找到有关 Azure SQL 数据库受到限制的证据。

SELECT *
FROM sys.dm_db_resource_stats
ORDER BY end_time DESC;

如果您看到 avg_log_write_percent 接近或等于 100%,则表示正在发生限制,您需要扩展数据库层。非高级层不适合 I/O 密集型工作负载,建议使用批处理。

当 Azure SQL 数据库发生节流时,您不仅会看到响应时间变慢,而且还会开始看到不成功的连接尝试和超时。

select * 
from sys.event_log 
where event_type <> 'connection_successful' and
start_time >= CAST(FLOOR(CAST(getdate() AS float)) AS DATETIME)
order by start_time desc

select *
from sys.database_connection_stats_ex
where start_time >= CAST(FLOOR(CAST(getdate() AS float)) AS DATETIME)
order by start_time desc

我只是想重现,但做不到。 SqlBulkCopy 运行 超过 30 分钟才取消它。

从 Azure 外部针对低 DTU Azure SQL 数据库尝试此操作:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        var constr = "Server=tcp:xxxxxx.database.windows.net,1433;Initial Catalog=xxxxxx;User ID=xxxxxx;Password=xxxxxx";


        using (var con = new SqlConnection(constr))
        {
            con.Open();

            var cmd = con.CreateCommand();
            cmd.CommandText = "create table #test(id int, data varbinary(max))";
            cmd.ExecuteNonQuery();

            var bc = new SqlBulkCopy(con);
            bc.DestinationTableName = "#test";
            bc.BulkCopyTimeout = 0;

            var dt = new DataTable();
            dt.Columns.Add("id", typeof(int));
            dt.Columns.Add("data", typeof(byte[]));
            var buf = Enumerable.Range(1, 1000 * 1000).Select(i => (byte)(i % 256)).ToArray();
            dt.BeginLoadData();
            for (int i = 0; i < 1000*1000*10; i++)
            {
                var r = dt.NewRow();
                r[0] = 1;
                r[1] = buf;
                dt.Rows.Add(r);
            }
            dt.EndLoadData();

            foreach (DataColumn col in dt.Columns)
            {
                bc.ColumnMappings.Add(col.ColumnName, col.ColumnName);
            }

            bc.NotifyAfter = 100;
            bc.SqlRowsCopied += (s, a) =>
            {
                Console.WriteLine($"{a.RowsCopied} rows copied");
            };


            Console.WriteLine($"Starting {DateTime.Now}");
            bc.WriteToServer(dt);
            Console.WriteLine($"Finished {DateTime.Now}");

        }
        Console.WriteLine("done");
    }


}

两个答案都很好,但我的问题似乎与代码无关。有一些 "glitch in the matrix" 似乎导致了我所看到的症状,在某一点之后我无法再重现它们。