如何在插入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
  • 控制台应用程序。
  • 使用短小精悍的

如何在插入37k行时避免.net连接池超时

首先:如果是关于性能的,请使用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批量复制/插入