【问题标题】:ADO.Net: reuse open SqlConnection or get a new one every time?ADO.Net:重用打开的 SqlConnection 还是每次都获取一个新的?
【发布时间】:2013-01-09 15:31:19
【问题描述】:

在发布这个问题之前,我已经阅读了这个网站上的几个答案:like thisthis。每个人似乎都同意“c# 应用程序池针对对同一数据库的多次调用进行了优化”。

但是,如果我从池中获得连接,我仍然会观察到显着的性能损失。以下是我的基准:

    private const string localConnString = "Data Source=(local);Integrated Security=SSPI;database=MyTest;Pooling=true";


    [Test]
    public void GetNewConnectionEveryTime()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        for (var i = 0; i < 1000; i++)
        {
            using (var conn = new SqlConnection(localConnString))
            {
                conn.Open();
                const string saveTrancount = "EXEC dbo.TestTran";
                ExecuteSql(conn, saveTrancount);
            }
        }
        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        //Time elapsed: 00:00:00.5576016
    }

    [Test]
    public void ReuseOneConnection()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        using (var conn = new SqlConnection(localConnString))
        {
            conn.Open();
            for (var i = 0; i < 1000; i++)
            {
                const string saveTrancount = "EXEC dbo.TestTran";
                ExecuteSql(conn, saveTrancount);
            }
        }
        stopwatch.Stop();
        Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
        //Time elapsed: 00:00:00.1110324
    }

    private void ExecuteSql(SqlConnection conn, string sql, int timeout = 0)
    {
        var command = conn.CreateCommand();
        command.CommandText = sql;
        command.CommandType = CommandType.Text;
        command.CommandTimeout = timeout;
        command.ExecuteNonQuery();
    }

显然,从池中获取连接所花费的时间(00:00:00.5576016 - 00:00:00.1110324 appr 0.44)比实际工作(第二个基准测试中的 00:00:00.1110324)多四倍。我错过了什么?

编辑:我针对在 RAM 磁盘上创建的数据库运行这些基准测试,因此我所有的数据库操作都非常快。

【问题讨论】:

    标签: sql-server-2008 c#-4.0 ado.net sql-server-2008-r2


    【解决方案1】:

    您的基准测试对我来说很有意义。如果您在没有连接池的情况下为每次迭代打开和关闭连接,情况会更糟,但这是一个完全不同的故事。 但是,当您关闭一个池连接时,您会将其返回到池中:在幕后,SNAC 发出 sp_reset_connection 并将连接放回池中。 通常,这是一个非常快的操作(除非发生阻塞),但它必须花费一些小但非零的时间。
    重复使用相同的连接而不关闭和打开每次迭代,避免了这个小滞后。
    但是,如果您比较池连接和非池连接的 相同 使用,这对我来说会更有意义。你试过吗?

    这是interesting post on sp_reset_connection

    【讨论】:

    • +1 您的回答和链接很有用。关于您的问题,我当然可以“比较池连接和非池连接的相同用途”,但它为什么有趣?我通常使用连接池。有什么情况我应该关掉它吗?
    • > 有什么情况需要关闭它吗?也许。通过故障转移群集和数据库镜像,您可能在故障转移后在池中出现无效连接。您可以重置池,而不是完全关闭池。不知道能不能回答你的问题。
    • 有一个 .net 平台可靠性更新,它会在重新使用之前检查连接是否仍然良好。如果 conn 不好,它将被透明地重新打开。这是 sql azure 的必备。
    • 这是很棒的信息!感谢分享。
    • @StrayCatDBA 有多个 .net 平台可靠性更新。你用过哪一个?
    【解决方案2】:

    +1 到@spaghettidba - 我同意,并添加一些 cmets .....

    我过去的方法是多次使用同一个连接 - 每次我一直假设(未测量)有一些连接时,我什至不必去连接池获取连接。 em> 成本正如@spaghettidba 所说。

    池的主要性能优势是它没有意义/无法重用相同连接实例的场景 - 在这种情况下,从池中获取以前使用过的连接要快得多,因为它没有实际上需要关闭并实际尝试连接到服务器,它只是假设它在那里并且可用 - 即 connection.Open() 在我的经验中,即使服务器关闭,池连接也不会出错 - 它只会出错当您尝试对连接执行任何操作时。

    【讨论】:

    • +1 是的,connection.Open() 不会调用我可以在 Profiler 中观察到的任何活动。当我对重用的连接运行命令时,我只会看到 sp_reset_connection。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2015-09-23
    • 2010-10-10
    • 2021-04-27
    相关资源
    最近更新 更多