【问题标题】:Is it better to execute many sql commands with one connection, or reconnect every time?一个连接执行多个sql命令,还是每次都重新连接更好?
【发布时间】:2011-05-12 16:36:12
【问题描述】:

这是我的测试代码,这似乎表明最好连接多次而不是只连接一次。

我做错了吗?

int numIts = 100;
Stopwatch sw = new Stopwatch();
sw.Start();
using (SqlConnection connection = new SqlConnection(connectionParameters))
{   
            connection.Open();
    for(int i = 0; i < numIts; i++)
    {
        SqlCommand command = new SqlCommand(sqlCommandName, connection);
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.AddWithValue(par1Name, par1Val);
                command.Parameters.AddWithValue(par2Name, par2Val);
        using(SqlDataReader reader = command.ExecuteReader())
        {
        }
    }
}
sw.Stop();
TimeSpan durationOfOneConnectionManyCommands = sw.Elapsed;
Console.WriteLine(durationOfOneConnectionManyCommands);

sw.Reset();

sw.Start();
for(int i = 0; i < numIts; i++)
{
    using (SqlConnection connection = new SqlConnection(connectionParameters))
    {   
                connection.Open();
        SqlCommand command = new SqlCommand(sqlCommandName, connection);
                command.CommandType = CommandType.StoredProcedure;
                command.Parameters.AddWithValue(par1Name, par1Val);
                command.Parameters.AddWithValue(par2Name, par2Val);
        using(SqlDataReader reader = command.ExecuteReader())
        {
        }
    }                               
}
sw.Stop();
TimeSpan durationOfManyConnections = sw.Elapsed;
Console.WriteLine(durationOfManyConnections);

输出:

//output:
//00:00:24.3898218   // only one connection established
//00:00:23.4585797   // many connections established.
//
//output after varying parameters (expected much shorter):
//00:00:03.8995448
//00:00:03.4539567

更新:

好的,所以那些说使用一个连接会更快的人拥有它。 (尽管差异很小,如果有的话。) 这是修改后的代码和输出:

public void TimingTest()
{
    numIts = 1000;
    commandTxt = "select " + colNames + " from " + tableName;

    OneConnection();
    ManyConnections();
    OneConnection();
}
private void ManyConnections()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < numIts; i++)
    {
        using (SqlConnection connection = new SqlConnection(connectionParameters))
        {
            connection.Open();
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = commandTxt;

                using (SqlDataReader reader = command.ExecuteReader())
                {
                }
            }
        }
    }
    sw.Stop();
    TimeSpan durationOfManyConnections = sw.Elapsed;
    Console.WriteLine("many connections: " + durationOfManyConnections);
}
private void OneConnection()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    using (SqlConnection connection = new SqlConnection(connectionParameters))
    {
        connection.Open();
        for (int i = 0; i < numIts; i++)
        {
            using (SqlCommand command = connection.CreateCommand())
            {
                command.CommandText = commandTxt;
                using (SqlDataReader reader = command.ExecuteReader())
                {
                }
            }
        }
    }
    sw.Stop();
    TimeSpan durationOfOneConnectionManyCommands = sw.Elapsed;
    Console.WriteLine("one connection: " + durationOfOneConnectionManyCommands);
}

输出:

one connection: 00:00:08.0410024
many connections: 00:00:08.7278090
one connection: 00:00:08.6368853

one connection: 00:00:10.7965324
many connections: 00:00:10.8674326
one connection: 00:00:08.6346272

更新:

如果我在每个函数之后使用SQLConnection.ClearAllPools(),差异会更加显着:

输出:

one connection: 00:00:09.8544728
many connections: 00:00:11.4967753
one connection: 00:00:09.7775865

【问题讨论】:

  • 这些数字太接近了,无法成为一个明确的基准!
  • +1 这个增量很小。尝试运行它几千次,看看你得到了什么。此外,重新排序这两个测试,因为一些启动时间无疑会影响您的结果。
  • 不仅时间几乎相等,而且您是在一个接一个地执行它们,由于代码已经加载和潜在的缓存,第二轮可能会更快。连接池是关键,在这里。
  • @n8wrl, @user420667: DbCommand 也实现了IDisposableSqlCommand 也是如此)。
  • 嗯...我会尝试重新排序和更多。但我认为我应该将我的命令更改为更快的命令,因为大部分时间都花在了命令的执行上。

标签: c# .net sql-server performance sqlconnection


【解决方案1】:

默认情况下,SqlConnection 将使用连接池。因此,在这两种情况下,您的代码很可能实际上不会打开许多​​连接。

您可以通过启用或禁用连接字符串中的池来控制 SqlConnection 是否使用池,具体取决于您的连接字符串用于哪个 DB,语法会有所不同。

如果您使用 MSSQLServer,请参阅here 了解一些信息。尝试在连接字符串中设置 Pooling=false 并查看它是否有所作为。

【讨论】:

    【解决方案2】:

    当然,最好有一个连接。也许您正在使用少量数据运行基准测试。尝试将数字增加到 1,000 或 10,000。

    另一点是,根据您的应用配置,您可能认为您正在使用多个连接运行,但 .NET 正在为您汇集连接,因此您基本上使用相同的连接运行。

    【讨论】:

      【解决方案3】:

      由于 .NET 重用连接(“连接池”),连续多次创建 DbConnection 的新实例并没有太多开销。 ADO.NET 只会在底层重用连接。这就是为什么每次都处理 SqlConnection 对象并告诉 .NET 它可以将其返回到池中的原因。

      但是,您可以使用ADO.NET batching 来提高多次插入的性能。在这种情况下,您每秒可以轻松地进行几 数千 次插入。如果性能很关键,您甚至可以考虑使用SQLBulkCopy

      另外,你的第一对结果很奇怪:100 次插入需要 30 秒?

      【讨论】:

      • 这仅适用于插入、更新和删除。本质上,仅用于写入数据库......而不是用于查询它。对吗?
      • @user420667:没错,批处理和批量复制加快了写入操作。抱歉,您最初的问题中没有查询文本,我假设您正在执行插入操作(部分是因为我最近必须优化大型插入操作,所以我做了各种性能测试)。
      • 嘿。考虑到我的 sqlcommand 有点故意含糊不清,这很公平。谢谢。
      【解决方案4】:

      一般来说,.NET 的连接池应该让它“无关紧要”,因为它可以很好地为您回收连接。但我的做法是使用单个连接来处理我知道将一起发生的一堆事务。我认为您的时间安排表明连接池正在完成其工作,并且只是运行中的简单变化。

      【讨论】:

        【解决方案5】:

        SqlClient 将汇集您的连接。在您打开的第一种情况下,它将完成打开连接的工作。每隔一个运行将使用池连接。如果您颠倒您的顺序并首先执行“许多连接”,我希望您会看到相反的结果。

        【讨论】:

          猜你喜欢
          • 2015-09-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-15
          • 1970-01-01
          • 2016-01-05
          • 1970-01-01
          相关资源
          最近更新 更多