我有一个具有适当索引的查询,并显示在查询计划中,估计子树成本约为 1.5。该计划显示一个索引查找,然后是键查找 - 这对于预期从 5 到 20 行的集合中返回 1 行的查询很好(即索引查找应该在 5 到 20 行之间找到,并且在 5 到 20 行之后)键查找,我们应该返回 1 行)。
当以交互方式运行时,查询几乎立即返回。然而,今天早上的数据库跟踪显示来自实时(网络应用程序)的运行时差异很大;通常,查询需要 < 100 次 DB 读取,并且实际上是 0 运行时......但是我们得到了一些消耗 > 170,000 次数据库读取的运行,并且运行时间长达 60 秒(大于我们的超时值)。
什么可以解释磁盘读取的这种变化?我曾尝试以交互方式比较查询,并使用来自两个并行运行的实际执行计划以及从快速和慢速运行中获取的过滤器值,但交互地这些实际上显示所使用的计划没有区别。
我还尝试确定可能锁定此查询的其他查询,但我不确定这会对 DB 读取产生如此大的影响……无论如何,在我的跟踪日志中,该查询往往是运行时最糟糕的。
更新:这是交互式运行查询时生成的计划示例:
请忽略“缺少索引”文本。确实,对当前索引的更改可以通过更少的查找实现更快的查询,但这不是这里的问题(已经有适当的索引)。这是一个实际执行计划,我们在其中看到诸如实际行数之类的数字。例如,在 Index Seek 上,实际行数为 16,I/O 成本为 0.003。I/O 成本与 Key Lookup 相同。
更新 2:此查询的跟踪结果是:
exec sp_executesql N'select [...column list removed...] from ApplicationStatus where ApplicationGUID = @ApplicationGUID and ApplicationStatusCode = @ApplicationStatusCode;',N'@ApplicationGUID uniqueidentifier,@ApplicationStatusCode bigint',@ApplicationGUID='ECEC33BC-3984-4DA4-A445-C43639BF7853',@ApplicationStatusCode=10
该查询是使用 Gentle.Framework SqlBuilder 类构建的,该类构建参数化查询,如下所示:
SqlBuilder sb = new SqlBuilder(StatementType.Select, typeof(ApplicationStatus));
sb.AddConstraint(Operator.Equals, "ApplicationGUID", guid);
sb.AddConstraint(Operator.Equals, "ApplicationStatusCode", 10);
SqlStatement stmt = sb.GetStatement(true);
IList apps = ObjectFactory.GetCollection(typeof(ApplicationStatus), stmt.Execute());