【问题标题】:Find out where sql server connections are being left open in c#找出在 c# 中 sql server 连接处于打开状态的位置
【发布时间】:2020-10-11 11:51:10
【问题描述】:

我继承了大量 C# dotnet 代码,这些代码显然在某些地方没有关闭与 sql server 的连接或其他东西,我得到了

The timeout period elapsed prior to obtaining a connection from the pool: This may have occurred because all pooled connections were in use and max pool size was reached

这种情况经常发生,而且通常同时发生,但我不知道有什么安排好的。手动搜索代码中的每一个小地方也是不可能的。任何想法如何在不手动检查代码中的每个函数的情况下解决这个问题?

【问题讨论】:

  • 这也可能是长时间运行查询的症状。检查服务器端活动。
  • 您可能不需要查看代码中的每个函数,只需查看数据访问代码和使用它的代码即可。你在使用 ORM 吗?如果有,是哪一个?
  • 你的意思是像实体框架? @sh1rts
  • @DanGuzman 与 spwho2 或类似的东西?
  • @TalC,是的 sp_who2 将报告来自应用程序的服务器端连接。我从您的其他评论中看到,您看到了数百个休眠连接。如果Last Batch 时间超过几分钟,则表明连接未正确关闭。在这种情况下,using 块是你的朋友。如果时间是最近的,则表明最近的活动高峰,可能与连接池错误相关。在这种情况下,查询和索引调优可能会有所帮助。

标签: c# asp.net sql-server entity-framework


【解决方案1】:

不想浏览代码的问题在于,它很可能不是单个实例或区域,并且可能取决于您在生产环境中获得最多流量的位置。您可以有一个看起来相当无害的查询,可以通过.AsNoTracking() 或更好的连接/包含而不是优化不佳的单个大查询来稍微改进。也有整个设计存在缺陷的情况(我曾经进入一个项目,其中 sql 连接附加到单个类,因此没有真正的方法将连接包装在 using 语句中。我们不得不重新构建它.

如果您使用自定义事务或 sql 连接请求,请确保使用 using 和 try catch finally 与 dispose 进行包装。依赖垃圾收集器并不总是很好,因为不能保证垃圾收集器实际上会在 using 语句的末尾立即出现 dispose

using (var conn = new SqlConnection())
{
    try
    {
        // Transactions, SQL Commands, etc
    }
    catch (SqlException ex)
    {
        // Trans rollback, error handling
    }
    finally
    {
        // Tell the garbage collector to clean up this resource now.
        conn.Dispose();
    }
}

如果您严格使用数据库上下文,则可以通过使用.AsNoTracking() 对某些语句进行微调,以用于仅检索结果集但无意修改该查询的结果的情况。类似于以下内容:

var tier = _dbContext.Tier.AsNoTracking()
    .Include(t => t.NameSchema)
    .Include(t => t.TierPackageGroups)
    .Where(t => t.TierNumber == tierNumber).FirstOrDefault();

确保尽可能使用连接或.Include,而不是延迟加载。

这不是您想听到的答案,而且我一直站在您的立场上,但很可能最好的解决方案是通过代码。你总是可以从清理几个区域开始,测量影响,再增加几个区域,测量影响等。这种蠕变调查可以帮助缩小你的搜索范围,因为你在某些方面看到了改进,或者在其他方面没有看到一些改进。

如果您确信它必须是您想要查找的单个查询,那么可以使用评估 sql 性能的工具,但我通常会请 DBA 来处理它,所以我不熟悉这些工具。如果您使用的是 Azure,则有一个面板,您可以在其中查看查询并按性能影响对它们进行组织。它不会将您指向代码,但它可以给您一个提示。

由于该问题专门针对不需要搜索代码的解决方案,因此另一个可行的答案是仅在问题上投入更多硬件,但这是一个糟糕的权宜之计,可能代价高昂且最终只是延迟问题或仅在 99% 的时间内解决问题(例如,直到您遇到交通高峰期)。我们几年前的一位客户可能已经花费了超过 50,000 美元的额外托管费用,而他们本可以让我们在最初提出请求时以不到 5,000 美元的价格解决问题。

【讨论】:

  • 感谢您的回复,手动搜索的问题基本上就像说谷歌有一个数据库池超时问题......去看看代码并修复它......我首先有隔离它来自哪里,因为查看整个代码对于一个人来说有点困难。我同意硬件不是这里的答案。我也知道关闭连接,它们中的大多数看起来都不错。另外,谢谢,我会调查一下这个。包括你提供的一些代码,因为我不熟悉。
  • 我确实看到 spwho2 有数百个休眠连接,知道这是否意味着什么吗?
  • 更明显的答案是未正确关闭的连接,但这可能会产生误导。如果您的查询花费的时间过长并且人们正在刷新页面,那么这些连接可能来自丢弃的请求,也可能是由于线程问题。不幸的是,我为您提供的最佳答案是根据我的个人经验削减代码。令人生畏?是的,但这是我得到一致结果的唯一方法。
  • 根据我的经验,您很可能不需要更多连接,并且有一个查询会减慢速度/超时/不关闭。只是想知道,但是在您遇到问题的窗口期间,您是否在数据库上运行了任何自动化?
  • 理论上,来自池的大多数查询可能需要 100 毫秒到 300 毫秒,因此您需要成千上万的用户来创建这种等待状态,除非您有超过 60 秒的查询那么可以肯定,正好 100 个或更多用户可能会导致这种情况(假设您的请求超时为 60 秒)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多