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

时间:2015-09-28 07:55:27

标签: c# sql-server task-parallel-library bulkinsert parallel.foreach

我正在尝试找出使用DAPPER将大约37k行批量插入我的Sql Server的最佳方法。

我的问题是,当我使用Parallel.ForEach时 - 数据库的连接数量会在短时间内增加 - 最终达到接近或大约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个左右的连接到数据库。连接池将释放连接(在连接池中保持实例化,等待使用)。如果Execute需要..我不知道..让我们说甚至1秒钟(插入的最长运行时间大约是500毫秒......而且每100个左右就有1个)......那没关系..该线程被阻塞并冷却,直到Execute完成。然后范围完成(并且Dispose被自动调用)并且连接已关闭。关闭连接后,Parallel.ForEach然后抓取集合中的下一个项目,转到连接池,然后抓取一个备用连接(记住 - 我们刚刚关闭一个,一分钟前)... rinse.repeat

这是错的吗?

注意:

  • .NET 4.5
  • Sql 2012
  • 控制台应用。
  • 使用Dapper.NET获取sql代码。

2 个答案:

答案 0 :(得分:1)

首先:如果是性能,请使用SqlBulkCopy。这适用于SQL-Server。如果您正在使用其他数据库服务器,那么它们可能有自己的SqlBulkCopy解决方案(Oracle有一个)。

SqlBulkCopy的作用类似于批量选择:一个状态打开一个连接,并将所有数据从服务器流式传输到客户端。使用插入,它以另一种方式工作:它将所有新记录从客户端流式传输到服务器。

请参阅: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:上述代码的多种变体是可能的。你可以从后台线程,任务等中调用它。我希望你明白这一点。

答案 1 :(得分:0)

您应该使用SqlBulkCopy而不是逐个插入。更快,更高效。

https://msdn.microsoft.com/en-us/library/ex21zs8x(v=vs.110).aspx

为答案所有者提供信用 Sql Bulk Copy/Insert in C#