如何在插入37k行时避免.net连接池超时
本文关键字:net 连接 超时 插入 37k | 更新日期: 2023-09-27 18:14:43
我正在尝试找出使用DAPPER批量插入约37k行到我的Sql Server的最佳方法。
我的问题是,当我使用Parallel.ForEach
时-到数据库的连接数量在短时间内增加-最终达到近100或大约100…这会导致连接池错误。如果我施加最大平行度,那么它就会达到最大值,并停留在那里。
设置maxdegree感觉不对。
它目前每秒执行10-20次插入。这也是在一个简单的控制台应用程序-所以有没有其他数据库活动除了发生在我的Parallel.ForEach
循环。
在这种情况下使用Parallel.ForEach
是不正确的事情,因为这不是cpu绑定?
我应该使用async/await
吗?如果是这样,是什么阻止它一次执行数百个db调用呢?
示例代码,这基本上就是我正在做的。
var items = GetItemsFromSomewhere(); // Returns 37K items.
Parallel.ForEach(items => item)
{
using (var sqlConnection = new SqlConnection(_connectionString))
{
var result = sqlConnection.Execute(myQuery, new { ... } );
}
}
我的(不正确的)理解是,在任何时候都应该有大约8个左右的连接到db。连接池将释放连接(在连接池中保持实例化,等待使用)。如果Execute
…我不知道……哪怕是1秒(插入的最长运行时间约为500毫秒)……这大约是每100人中有1人)……没关系……该线程被阻塞并冻结,直到Execute
完成。然后作用域完成(Dispose
被自动调用),连接关闭。关闭连接后,Parallel.ForEach
抓取集合中的下一个项目,进入连接池,然后抓取一个备用连接(记住——我们刚刚关闭了一个,就在一瞬间)……rinse.repeat .
这是错的吗?
指出:
- 。NET 4.5
- Sql 2012
- 控制台应用程序。 使用短小精悍的
- 。
首先:如果是关于性能的,请使用SqlBulkCopy。这适用于SQL-Server。如果您正在使用其他数据库服务器,它们可能有自己的sqlbulkcopy解决方案(Oracle有一个)。
SqlBulkCopy的工作原理类似于bulk-select:一个状态打开一个连接,并将所有数据从服务器流式传输到客户端。对于insert,它的工作方式正好相反:它将所有新记录从客户端流式传输到服务器。
见:https://msdn.microsoft.com/en-us/library/ex21zs8x (v = vs.110) . aspx
如果您坚持使用并行性,您可能需要考虑以下代码:
void BulkInsert<T>(object p)
{
IEnumerator<T> e = (IEnumerator<T>)p;
using (var sqlConnection = new SqlConnection(_connectionString))
{
while(true)
{
T item;
lock(e)
{
if (!e.MoveNext())
return;
item = e.Current;
}
var result = sqlConnection.Execute(myQuery, new { ... } );
}
}
}
现在创建您自己的线程,并在这些线程上使用同一个形参调用此方法:遍历您的集合的迭代器。每个威胁打开一次自己的连接,开始插入,在所有物品插入后,连接关闭。此解决方案使用与创建的线程相同数量的连接。
PS:以上代码可能有多种变体。你可以从后台线程,任务等等调用它。我希望你能明白。
您应该使用SqlBulkCopy而不是逐个插入。
https://msdn.microsoft.com/en-us/library/ex21zs8x (v = vs.110) . aspx
给答案所有者的积分Sql批量复制/插入