【发布时间】:2021-10-31 07:08:07
【问题描述】:
我正在我们的网络应用程序中开发一个导入器。使用我目前拥有的代码,当您通过本地 SQL 服务器连接时,它运行良好且在合理范围内。我还在创建一个.sql 脚本,他们也可以下载它
示例 1
4 万条记录,8 列,从 1 分 30 秒到 2 分钟
当我将其移至生产和 Azure 应用服务时,它的运行速度非常慢。
示例 2
40k 条记录,8 列,从 15 分钟到 18 分钟
当前数据库设置为:定价层:标准 S2:50 个 DTU
代码如下:
using (var sqlConnection = new SqlConnection(connectionString))
{
try
{
var generatedScriptFilePathInfo = GetImportGeneratedScriptFilePath(trackingInfo.UploadTempDirectoryPath, trackingInfo.FileDetail);
using (FileStream fileStream = File.Create(generatedScriptFilePathInfo.GeneratedScriptFilePath))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
sqlConnection.Open();
sqlTransaction = sqlConnection.BeginTransaction();
await writer.WriteLineAsync("/* Insert Scripts */").ConfigureAwait(false);
foreach (var item in trackingInfo.InsertSqlScript)
{
errorSqlScript = item;
using (var cmd = new SqlCommand(item, sqlConnection, sqlTransaction))
{
cmd.CommandTimeout = 800;
cmd.CommandType = CommandType.Text;
await cmd.ExecuteScalarAsync().ConfigureAwait(false);
}
currentRowLine++;
rowsProcessedUpdateEveryXCounter++;
rowsProcessedTotal++;
// append insert statement to the file
await writer.WriteLineAsync(item).ConfigureAwait(false);
}
// write out a couple of blank lines to separate insert statements from post scripts (if there are any)
await writer.WriteLineAsync(string.Empty).ConfigureAwait(false);
await writer.WriteLineAsync(string.Empty).ConfigureAwait(false);
}
}
}
catch (OverflowException exOverFlow)
{
sqlTransaction.Rollback();
sqlTransaction.Dispose();
trackingInfo.IsSuccessful = false;
trackingInfo.ImportMetricUpdateError = new ImportMetricUpdateErrorDTO(trackingInfo.ImportMetricId)
{
ErrorLineNbr = currentRowLine + 1, // add one to go ahead and count the record we are on to sync up with the file
ErrorMessage = string.Format(CultureInfo.CurrentCulture, "{0}", ImporterHelper.ArithmeticOperationOverflowFriendlyErrorText),
ErrorSQL = errorSqlScript,
RowsProcessed = currentRowLine
};
await LogImporterError(trackingInfo.FileDetail, exOverFlow.ToString(), currentUserId).ConfigureAwait(false);
await UpdateImportAfterFailure(trackingInfo.ImportMetricId, exOverFlow.Message, currentUserId).ConfigureAwait(false);
return trackingInfo;
}
catch (Exception ex)
{
sqlTransaction.Rollback();
sqlTransaction.Dispose();
trackingInfo.IsSuccessful = false;
trackingInfo.ImportMetricUpdateError = new ImportMetricUpdateErrorDTO(trackingInfo.ImportMetricId)
{
ErrorLineNbr = currentRowLine + 1, // add one to go ahead and count the record we are on to sync up with the file
ErrorMessage = string.Format(CultureInfo.CurrentCulture, "{0}", ex.Message),
ErrorSQL = errorSqlScript,
RowsProcessed = currentRowLine
};
await LogImporterError(trackingInfo.FileDetail, ex.ToString(), currentUserId).ConfigureAwait(false);
await UpdateImportAfterFailure(trackingInfo.ImportMetricId, ex.Message, currentUserId).ConfigureAwait(false);
return trackingInfo;
}
}
问题
- 有没有办法在 Azure 上加快这个速度?或者是升级
DTUs的唯一方法? - 我们也在研究 SQL 批量复制。这是否会帮助或仍然会导致 Azure 运行缓慢:https://docs.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlbulkcopy?redirectedfrom=MSDN&view=dotnet-plat-ext-5.0
期望的结果
在本地 SQL Server 数据库中运行时以相同的速度运行
【问题讨论】:
-
记住数据库离你很远......所以你必须做一些事情来减少往返......批量操作是一种方法
-
@Ctznkane525 击败了我,但您的方法似乎与您发布的时间一致 - 15 分钟内有 4 万条记录,即 90 万毫秒,每次往返大约 22.5 毫秒。在本地,根据您发布的时间(或每次往返 2.25 毫秒),您运行相同工作负载的速度大约快了 10 倍,这是有道理的。您可以从 Azure VM(Azure SQL DB 本地)运行它并查看结果是否更接近您的本地测试?
-
SqlBulkCopy将大大加快速度。而且您的代码无论如何都有问题:缺少参数化,并且在事务对象上缺少using块 -
如果不是发送单独的插入,而是构建一个包含所有插入的命令并在数据库中只运行一次,会发生什么?
-
您正在执行 RBAR 插入,这是将数据放入数据库的最慢方法。将数据发送到服务器一次,分批处理,性能提升一个数量级。
标签: c# sql azure-sql-database sqlbulkcopy