gpt4 book ai didi

C# 数据库中的多个并行插入

转载 作者:太空狗 更新时间:2023-10-29 22:10:36 25 4
gpt4 key购买 nike

我有一个包含大约 3000 行的数据表。这些行中的每一行都需要插入到数据库表中。目前,我正在运行一个 foreach 循环,如下所示:

obj_AseCommand.CommandText = sql_proc;
obj_AseCommand.CommandType = CommandType.StoredProcedure;
obj_AseCommand.Connection = db_Conn;
obj_AseCommand.Connection.Open();

foreach (DataRow dr in dt.Rows)
{
obj_AseCommand.Parameters.AddWithValue("@a", dr["a"]);
obj_AseCommand.Parameters.AddWithValue("@b", dr["b"]);
obj_AseCommand.Parameters.AddWithValue("@c", dr["c"]);

obj_AseCommand.ExecuteNonQuery();
obj_AseCommand.Parameters.Clear();
}

obj_AseCommand.Connection.Close();

请问我如何在数据库中并行执行 SP,因为上述方法大约需要 10 分钟才能插入 3000 行。

最佳答案

编辑

事后看来,使用 Parallel.ForEach 来并行化数据库插入有点浪费,因为它还会为每个连接消耗一个线程。可以说,更好的并行解决方案是使用 System.Data Db 操作的异步版本,例如 ExecuteNonQueryAsync ,开始执行(并发),然后使用 await Task.WhenAll() 等待完成 - 这将避免调用者的线程开销,尽管整体 Db 性能可能不会有任何更快。 More here

原始答案,多个并行插入数据库

您可以使用 TPL 并行执行此操作,例如特别是 localInit 重载 Parallel.ForEach .您几乎肯定会想通过调整 MaxDegreeOfParalelism 来限制并行度。这样你就不会淹没你的数据库:

Parallel.ForEach(dt.Rows,
// Adjust this for optimum throughput vs minimal impact to your other DB users
new ParallelOptions { MaxDegreeOfParallelism = 4 },
() =>
{
var con = new SqlConnection();
var cmd = con.CreateCommand();
cmd.CommandText = sql_proc;
cmd.CommandType = CommandType.StoredProcedure;
con.Open();

cmd.Parameters.Add(new SqlParameter("@a", SqlDbType.Int));
// NB : Size sensitive parameters must have size
cmd.Parameters.Add(new SqlParameter("@b", SqlDbType.VarChar, 100));
cmd.Parameters.Add(new SqlParameter("@c", SqlDbType.Bit));
// Prepare won't help with SPROCs but can improve plan caching for adhoc sql
// cmd.Prepare();
return new {Conn = con, Cmd = cmd};
},
(dr, pls, localInit) =>
{
localInit.Cmd.Parameters["@a"] = dr["a"];
localInit.Cmd.Parameters["@b"] = dr["b"];
localInit.Cmd.Parameters["@c"] = dr["c"];
localInit.Cmd.ExecuteNonQuery();
return localInit;
},
(localInit) =>
{
localInit.Cmd.Dispose();
localInit.Conn.Dispose();
});

注意事项:

  • 除非您真的知道自己在做什么,否则通常我们应该让 TPL 来决定并行度。但是,根据资源的争用程度(读取:数据库工作的锁),可能需要限制并发任务的上限(试错可能有用,例如尝试并发 4、8、16 个并发任务等以查看哪个提供了最大的吞吐量,并监控 Sql Server 上的锁定和 CPU 负载。
  • 同样,保留 TPL 的默认分区程序通常足以跨任务对 DataRow 进行分区。
  • 每个任务都需要自己独立的 Sql 连接。
  • 与其在每次调用时创建和处理命令,不如为每个任务创建一次,然后继续重复使用相同的命令,每次只更新参数。
  • 使用 LocalInit/Local Finally lambda 执行每个任务的设置和清理,例如处理命令和连接。
  • 您也可以考虑使用 .Prepare()如果您使用的是 AdHoc Sql 或 Sql versions prior to 2005
  • 我假设枚举DataTable 的 行是线程安全的。当然,您需要仔细检查一下。

旁注:

3000 行的 10 分钟时间过长,即使是宽表和单线程也是如此。你的程序是做什么的?我假设处理不是微不足道的,因此需要存储过程,但如果你只是做简单的插入,根据@3dd 的评论,SqlBulkCopy将在相当窄的表上每分钟产生约 100 万行的插入。

关于C# 数据库中的多个并行插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27774265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com