Rei*_*l-- 3 c# sql-server sqlbulkcopy task-parallel-library async-await
为什么async在单个事务上针对不相关的表并行运行多个 SqlBulkCopy 插入看起来就像串行运行一样?
我有一些代码正在计算和存储大量数据。计算是预先完成的,因此代码的存储部分得到了要存储的一大堆数据。
我的数据库写入正在完成,SqlBulkCopy.WriteToServerAsync一般来说,它可以很好地完成工作。
我需要存储6个与业务相关的表,但与SQL无关。因此,我对它们的写入需要在一个事务中进行,以便任何一个写入上的错误都会恢复所有其他写入上的写入。
该代码的性能相当关键,因此我希望能够并行运行 BulkInsert。没有 FKey 或任何其他与之交互的表(数据完整性由代码管理),因此我看不出有任何理由认为这是不可能的。
我以为我知道如何编写所有代码并且能够使其全部正常工作,但是有一个我不明白的奇怪的性能下降:
很高兴提供您想要的实际代码位,但这已经是一个很长的 Q,并且代码会很长到 0。如果你确实想看什么,LMK。
我可以写:
“按顺序批量插入到每个表中,全部在单个事务中”。
new SqlConnection()and .BeginTransaction(),foreach翻了6张桌子,await InsertToTable(transaction)每张桌子都移动foreach到下一张桌子。foreach结束时我.Commit()进行事务并关闭连接。“按顺序批量插入每个表,每个表都有一个新的连接和事务。”
foreach遍历了 6 个表,并且await InsertToTable()每个表在foreach移动到下一个表之前。InsertToTable()调用中,我都会打开一个新的SqlConnectionand BeginTransaction,然后在从方法返回之前打开.Commit()一个 and 。.Close()“并行批量插入每个表,每个表都有一个新的连接和事务。”
thisTableTask = InsertToTable()即,我通过调用每个表并捕获Tasks 但尚未对 await它们进行 ing来启动所有 6 个任务。await Task.WhenAll()捕获了 6 个任务。InsertToTable()调用中,我都会打开一个新的SqlConnectionand BeginTransaction,然后在从方法返回之前打开.Commit()一个 and 。.Close()(但请注意,foreach 已移至下一个表,因为它不会await立即执行任务。“并行批量插入每个表,全部在单个事务中”。
new SqlConnection()and .BeginTransaction()。thisTableTask = InsertToTable(transaction)然后,我通过调用每个表并捕获Tasks 但尚未对 它们进行 ing来启动所有 6 个任务await。await Task.WhenAll()捕获了 6 个任务。WhenAll结束,我就.Commit()进行事务并关闭连接。在所有情况下,最终的 BulkInsert 如下所示:
using (var sqlBulk = BuildSqlBulkCopy(tableName, columnNames, transactionToUse))
{
await sqlBulk.WriteToServerAsync(dataTable);
}
private SqlBulkCopy BuildSqlBulkCopy(string tableName, string[] columnNames, SqlTransaction transaction)
{
var bulkCopy = new SqlBulkCopy(transaction.Connection, SqlBulkCopyOptions.Default, transaction)
{
BatchSize = 10000,
DestinationTableName = tableName,
BulkCopyTimeout = 3600
};
foreach (var columnName in columnNames)
{
// Relies on setting up the data table with column names matching the database columns.
bulkCopy.ColumnMappings.Add(columnName, columnName);
}
return bulkCopy;
}
Run Code Online (Sandbox Code Playgroud)
如上所列
前 3 个结果对我来说都很有意义。
#1 vs #2:只要插入全部有效,事务就不会做太多事情。数据库仍在相同的时间点执行所有相同的工作。
#2 vs #3:这就是并行运行插入的全部要点。通过并行运行插入,我们等待 SQL 完成任务的时间更少。我们让数据库并行执行大量工作,因此速度虽然没有提高 6 倍,但仍然足够了。
为什么最后一个案例这么慢?我可以修复它吗?
这几乎与串行执行一样慢,并且比并行执行慢了整整 25%,但有多个事务!
这是怎么回事?为什么async在单个事务上针对不相关的表并行运行多个 SqlBulkCopy 插入看起来就像串行运行一样?
SqlBulkCopy 多个表在单个事务下插入或实体框架和经典 Ado.net 之间的批量插入操作(不并行运行查询)
在一个事务中对多个相关表使用 SqlBulkCopy(表是相关的,并且它们试图从中读回)
使用 SqlBulkCopy 和 Azure 进行并行批量插入(即并行加载到单个表中)
| 归档时间: |
|
| 查看次数: |
2099 次 |
| 最近记录: |