相同的SQL查询是快速还是慢,具体取决于执行上下文

时间:2017-12-22 10:54:11

标签: sql-server entity-framework linq

我遇到了一个奇怪的现象,然后调查了一个典型的ASP.NET MVC应用程序的慢视图。其中一个查询运行速度非常慢,没有明显的原因。有问题的LINQ查询看起来像这样(DbDbContext):

var testResults = Db.CustomTestResults
    .Include(tr => tr.TestMachine.Platform)
    .Include(tr => tr.TestCase)
    .Include(tr => tr.CustomTestResultAnalysis.Select(tra => tra.AnalysisOutcomeData))
    .Where(tr => tr.CustomTestBuildId == testBuild.Id)
    .ToList()
    .AsReadOnly();
实际上没什么特别的。根据过滤器查询结果集的大小可能会有所不同,最大值为10到10000条记录

从SSMS执行的SQL生成的查询(由LINQ调试日志捕获)运行速度很快,最大集合大约需要2秒,小集合运行不到1秒。然而,由IIS运行奇怪的事情发生。查询开始运行速度慢~1 / 100x。较小的执行需要大约10秒,由于查询执行超时,较大的执行失败。我不确定是否有任何其他查询受到影响,但这只是处理大型数据集,所以注意到这个问题最为明显。

由于这并不令人困惑,因此相同的代码在不久前的预期中运行得非常完美。所以这个bug似乎是由一些外部因素造成的。数据库是SQL Server 2014 SP2,EF是v6.2,IIS 7.5。

非常感谢在哪些方面有任何想法,以及我如何进一步调查这一点。

2 个答案:

答案 0 :(得分:1)

事实证明,问题出在SQL Server优化中,它在多次运行类似查询后开始运行一段时间。可以通过对原始查询的任何非相关更改来检测此问题,这会在一段时间内修复性能。

controlling query command options可以正确缓解此行为。 EF的解决方案之一是demonstrated here

作为一种临时的“快速而肮脏”的解决方案,我每次都使用这种方法随机化查询,从而阻止了SQL Server引擎的优化:

private static IQueryable<CustomTestResult> RandomizeQuery(IQueryable<CustomTestResult> query)
{
    const int minConditions = 1;
    const int maxConditions = 5;
    const int minId = -100;
    const int maxId = -1;

    var random = new Random();
    var conditionsCount = random.Next(minConditions, maxConditions);
    for (int i = 0; i < conditionsCount; i++)
    {
        var randomId = random.Next(minId, maxId);
        query = query.Where(test => test.Id != randomId);
    }

    return query;
}

答案 1 :(得分:0)

由于SQL没有改变但是根据你运行的平​​台出现问题,我会从你的设置开始。 Erland Sommarskog写了一篇关于为什么和做什么的伟大参考:http://www.sommarskog.se/query-plan-mysteries.html

很长,但我想你会在那里找到答案。