1

在数据库中执行许多插入时,我通常会有这样的代码:

using (var connection = new SqlConnection(connStr))
{
  connection.Open();
  foreach (var item in items)
  {
     var cmd = new SqlCommand("INSERT ...")
     cmd.ExecuteNonQuery();
  }
}

我现在想对数据库进行分片,因此需要根据插入的项目选择连接字符串。这将使我的代码运行得更像这样

foreach (var item in items)
{
  connStr = GetConnectionString(item);
  using (var connection = new SqlConnection(connStr))
  {
    connection.Open();      
    var cmd = new SqlCommand("INSERT ...")
    cmd.ExecuteNonQuery();
  }
}

这基本上意味着它正在为每个项目创建一个到数据库的新连接。这会起作用还是会为每个插入重新创建连接会导致可怕的开销?

4

3 回答 3

3

我假设您在谈论 C#/.NET。在这种情况下,连接由框架池化,因此以这种方式创建它们的开销并没有那么高。

编辑

正如@TomTom 所指出的,还应考虑交易。如果您要插入到同一服务器上的不同数据库中,您可以使用普通的 SQL 事务。如果数据库位于不同的服务器上,则需要使用 MSDTC 事务在数据库服务器之间进行协调。无论如何,处理事务的最佳方法是将相关代码包装在 TransactionScope 中。这与打开和关闭(实际上是从池中重用)数据库连接不冲突。

using(new TransactionScope())
{
    // Update code to various databases, opening and closing connections.
}

对于 SQL2005 或更高版本,TransactionScope 将首先默认为 SQL 事务,然后在需要时自动将其升级为 MSDTC 事务。

于 2010-03-27T13:40:07.360 回答
1

从理论上讲,创建尽可能多的连接是可以的。除非您强制非连接池,否则重新创建连接很快。每个标准 SQL 连接不会关闭,而是放入池中(两分钟,iirc)以供重用。

也就是说,如果您为每个插入打开一个新连接,您就会遇到严重的问题 - 您的事务边界。更复杂的更新需要属于一个事务。虽然 yoyu 可以将其包装在 System.Transaction 命名空间下... ...这意味着所有连接将保持打开状态,直到提交,用完很多连接,这将强制 MSDTC(分布式事务协调器)介入 - 承担所有开销。

因此,从架构的角度来看,重用连接更为可取。您基本上处于事务行为的死胡同,而不是连接数。

于 2010-03-27T13:42:58.377 回答
1

除了其他海报提出的观点外,你所说的模式是你一贯的风格,让我想起了我刚刚读到的东西。

http://research.microsoft.com/apps/pubs/?id=76507

2.3 识别批量操作的机会

考虑应用程序代码中的一个循环,如下所示,应用程序在其中将数据插入到表中:

for (int i=0;i<MAXVALUE;i++) {
// execute SQL statement INSERT INTO T VALUES(...)
}

如上所述,代码效率低下,因为每次循环都会执行一个 INSERT 语句。实现相同结果的一种更有效的方法是使用数据访问层的批量插入 API,它利用了批处理的优势。请注意,识别此问题的要素是具有在循环内重复执行特定 SQL 语句的应用程序上下文,以及知道每个实例实际上是表 T 上的 INSERT 语句的数据库上下文。然后可以将这些信息放在一起,建议映射到批量插入 API。

在 ADO.NET 2.0 中,我认为这意味着使用SqlBulkCopy

于 2010-03-27T18:54:43.060 回答