优化 SQL 服务器的性能(大量等待任务)

Optimize Performance of SQL Server (a lot of waiting tasks)

我的数据库(Microsoft SQL 服务器)有问题,我们有很多用户使用我们的 API,这个 API 对我们的数据库进行了很多查询(这很正常,因为我们正在保存跟踪数据),我们正在为 API 使用负载均衡器,因此我们可以处理很多请求,但这给我们带来了问题,即早上一切正常,但当一天过去了,一切都变得非常缓慢,我查看了 activity 监视器(我不是 DBA,但团队没有监视器),我注意到当它变慢时等待任务增加,它总是大于 500(等待任务总是在 500-800 左右),因此我和我的经理谈过,他也不是技术人员,我们租了一台服务器,它只会 运行 数据库,这些是规格:

服务器规格:

但问题是一样的:

我查看了任务管理器,我注意到它甚至没有使用 100% 的 ram 或 cpu:

所以我希望专家可以推荐我做什么,因为我有硬件但它没有改进:(,提前致谢。

一些相关信息:

我最近在 sql 服务器上看到了这个问题。请在 google 中搜索锁争用。您的数据库正在执行其工作,需要锁定以进行更新和插入。这是保持数据一致性所必需的。这是一致性和速度(=并发)之间的权衡。您需要查看应用程序层并尝试使您的事务更短。您还应该查看您的事务隔离级别。 Serialisable 并不总是需要的,并且在有很多锁定时是一个糟糕的选择。请搜索隔离级别以及如何选择隔离级别。 或许您应该与您的开发人员讨论 READ_COMMITTED_SNAPSHOT。如果您考虑 read_commited_snapshot,请查看 tempdb 使用情况,它会变得更高。 这说起来容易做起来难。我知道。如果您可以锁定,您的服务器将自动变得更快。这就是为什么您看不到 CPU 和 RAM 的大量使用。大部分时间都在等待。优化您的交易。

尝试在进行更改之前制定性能基准,以便您可以衡量更改是否具有积极影响。

简而言之:

  • 检查隔离级别
  • 检查您的交易
  • 制定基准
  • 想想READ_COMMITTED_SNAPSHOT
  • 检查你的索引。
  • 反馈会很好 :-)

我看到一个被阻止的交易。会有一个拦截器。如果您发现 head 阻塞程序是一个可以优化的查询,那将是一个开始的地方。这些是简单的单一查询事务还是一个事务中的多个查询?您是否正在做一些强制插入为单线程的事情,例如获取最后一个 ID 并为插入的新 ID 添加 1?它是否必须阻止其他交易?

例如,在繁忙的数据库中我们处理了新记录。我们进行了快速读取以获取要处理的最后一条记录。然后我们使用 where 子句只处理该记录之前的记录。否则,插入将被事务阻塞,直到处理完所有记录。

如果实施不当,Entity Framework 肯定会给数据库带来过度的负载,因此这是探索的一种途径。然而,它确实需要调查可能的罪魁祸首和具体的优化来消除它们。

我遇到的最常见的 EF 性能问题如下:

  1. 延迟加载命中。这是开发人员编写查询来加载实体的地方,然后遍历它们以访问相关实体,这会触发更多 SQL 调用来加载这些单独的实体。当 运行 超过实体集时,这会导致大量不必要的查询。在需要这些实体的地方急切加载相关实体 (Include) 可以用 JOIN 替换这些额外的数据库命中。更好的是,通过 Select 利用投影可以产生更高效的查询。

  2. 加载太多数据,太频繁了。像放错地方的 ToList 调用这样简单的事情可能意味着锁定了比需要的多得多的行。这通常是由于开发人员面临他们想要根据计算值过滤数据(即方法结果等无法转换为 SQL)并且“修复”是添加 ToList 然后它神奇地工作。在幕后,EF 正在将大量未过滤的数据从服务器具体化到内存。此处的解决方法是重新散列过滤,以便更多过滤深入查询以减少被拉回的数据量。

像 Generic Repository 类 这样的东西对于这些类型的问题来说是一个致命的放弃,其中存储库 return 支持整个实体或实体集合,其中更有效的选项可用。

经典例子包括:

  • 取回一个实体只是为了检查它是否为空。 (改用 .Any() 查询)
  • 取回实体列表只是为了获得计数。 (改用 .Count() 查询)
  • 获取只需要少量列的实体。 (改为使用 .Select() 的投影)

EF 可以构建非常高效的查询,但如果实施不当,它可能会导致数据库交互噩梦。不幸的是,如果不深入研究代码并 运行 与分析器一起使用,就无法列出有帮助的具体改进。