【问题标题】:Entity Framework ToListAsync sometimes hangs, sometimes resolves实体框架 ToListAsync 有时会挂起,有时会解决
【发布时间】:2020-11-09 18:33:33
【问题描述】:

我一直致力于将 ASP.NET MVC 仪表板页面转换为使用异步实体框架方法,但遇到了一个问题,有时调用会无限期挂起并出现 no 错误或挂起持续时间 > 1 分钟并解决。这种行为是零星的,我还没有找到复制它的方法。这是我的 EF 调用之一,当然是经过消毒的。

注意:sqlparameters 对象在上面定义。 sql 是一个字符串形式的查询。

using (var context = new BaseDbContext())
{
    return await context.Database.SqlQuery<MyViewModel>(sql, parameters.ToArray()).ToListAsync();
}

但是,这不是唯一会挂起的查询。有时其他查询会挂起,有些是用 linq to sql 编写的,有些是使用上述实际 sql 查询的。

重要提示

  • 我一直使用 async/await 直到我的控制器,包括我的控制器方法本身。
  • 有时一切都运行良好 - 所有异步调用都正常运行,一切都在几秒钟内加载完毕。
  • “挂起”行为是偶发的。有时它不会在几个小时内发生,有时它会在我每次启动应用程序时发生。

编辑 来自 cmets 的 Andres 的建议可能为我指明了正确的方向,至少可以看看。在几个小时没有问题后挂断时,我设法赶上了该程序。 SQL Profiler 发现了几个RPC:Completed 事件,这些事件对于非常简单的选择(在 SSMS 中运行时需要几分之一秒才能完成)花费了 15-65 秒以上。所有这些都相当接近。

我已经清理并将正在运行的 SQL 放在下面,并添加了开始/结束时间以添加上下文。

exec sp_executesql N'SELECT * FROM Reports.dbo.Customers WHERE Date = @Par1',N'@Par1 datetime',@Par1='2020-07-20 00:00:00'

开始时间:14:22:08.597

结束时间:14:22:23.197

exec sp_executesql N'SELECT * FROM Reports.dbo.Customers WHERE Date = @Par1',N'@Par1 datetime',@Par1='2019-07-20 00:00:00'

开始时间:14:22:23.267

结束时间:14:22:37.357

exec sp_executesql N'SELECT * FROM Reports.dbo.Policies WHERE Date = @Par1 OR Date = @Par2',N'@Par1 datetime,@Par2 datetime',@Par1='2020-07-20 00:00:00',@Par2='2020-06-20 00:00:00'

开始时间:14:22:38.200

结束时间:14:23:42.333

exec sp_executesql N'SELECT * FROM Reports.dbo.Policies WHERE Date = @Par1',N'@Par1 datetime',@Par1='2020-07-20 00:00:00'

开始时间:14:23:46.863

结束时间:14:23:58.773

还有一个更难清理的 Entity Framework 查询,耗时约 6 秒,还有一个看起来很可疑的 Audit Logout 事件。该事件的开始时间为 14:18:25.753,结束时间为 14:23:25.770。

虽然我在解释这些结果方面没有大量知识,但在我看来,由于 MVC 应用程序中的所有内容都是异步/等待,因此问题可能是多个查询在相似的时间访问同一个数据库表?在将仪表板转换为 async/await 之前,我不相信这实际上会挂起。

编辑 2 根据 Andres 的回答以及我在 SQL Profiler 中向我的跟踪添加附加信息后所学到的知识(请参阅下面该答案下方的评论),似乎表锁定是罪魁祸首——但是我正在努力寻找有关如何解决这个问题。我猜我们可能不得不回滚到对所有内容使用同步数据库调用而不是异步?

【问题讨论】:

  • 我强烈建议您使用 SQL Server Profiler 来跟踪查询。也许在数据库级别有一些阻塞。你知道怎么用吗?
  • 试试..ConfigureAwait(false)
  • 会试试这个建议@Nick。需要我一点时间,因为我将不得不将它添加到整个班级,但一旦我做出改变,我会更新你。
  • @Andres 我没有,但我的经理可能会。如果尼克的建议不起作用,我将与他联系以分析查询。
  • @Nick 为耽搁道歉,我被拉去开会。我已将 .ConfigureAwait(false) 添加到存储库中的所有调用中,但是此问题仍在继续发生。我成功地加载了仪表板,然后我在帖子中遇到了 EF 调用挂起,花了大约 3 分钟来解决。

标签: c# asp.net-mvc entity-framework async-await


【解决方案1】:

我在回答添加一些图片,我在cmets中不能这样做:

正如我所说,使用 SQL Server Profiler 来跟踪查询。这可能与数据库级别的某种阻塞或问题有关。

我建议您添加一些事件以了解正在发生的事情的更多信息:

添加这些事件:

交易:

:

锁:

通过这些事件,您可以检查事务何时开始以及何时结束。 您应该在中间看到 RCP 调用。 此外,通过 Locks 事件,您应该能够查看是否有任何阻塞事务正在锁定您的查询。

如果您的 RCP 持续时间(参见列)较长,则问题出在 SQL Server 中。可能是由于表锁定。

首先检查这些事件。如果您在生产环境中使用这些事件运行分析器,请小心,它会消耗系统资源。

【讨论】:

  • 我刚刚将这些事件类型添加到跟踪中并重新运行 - 幸好程序在第一次尝试时挂起。没有捕获到Lock:Deadlock 事件。捕获了数百万个Lock:AcquiredLock:Released 事件。之前的 RPC:Complete 事件花费了过多的时间,表现类似——每个事件的长度约为 14-70 秒。那么,这似乎表明表锁定是罪魁祸首。
  • @CthuluHoop 我不是说你有死锁,而是锁。如果表被锁定,您的新查询事务将等到表的锁被释放。您应该使用 DBA 对此进行分析。也许您同时有很多插入/更新/删除查询。还要检查是否没有定期运行的大规模更新/插入/删除进程。插入许多实体的 api 也可能是问题所在。比方说,您插入 100 个对象,Entity Framework 将它们一一插入到事务中。在事务提交之前,表被锁定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
相关资源
最近更新 更多