选择前10名...并选择前30名遵循不同的执行计划

obj*_*box 10 sql-server query-optimization sql-server-2008-r2

在查询优化期间,我包含了sql server(Sql Server 2008 R2 Enterprise)的奇怪行为.我在表上创建了几个索引,以及一些索引视图.我有两个查询,例如:

select top 10 N0."Oid",N1."ObjectType",N1."OptimisticLockField" from ((("dbo"."Issue" N0
 inner join "dbo"."Article" N1 on (N0."Oid" = N1."Oid"))
 inner join "dbo"."ProductLink" N2 on (N1."ProductLink" = N2."Oid"))
 inner join "dbo"."Technology" N3 on (N2."Technology" = N3."Oid"))
where (N1."GCRecord" is null and (N0."IsPrivate" = 0) and ((N0."HasMarkedAnswers" = 0) or N0."HasMarkedAnswers" is null) and (N3."Name" = N'Discussions'))
order by N1."ModifiedOn" desc
Run Code Online (Sandbox Code Playgroud)

select top 30 N0."Oid",N1."ObjectType",N1."OptimisticLockField" from ((("dbo"."Issue" N0
 inner join "dbo"."Article" N1 on (N0."Oid" = N1."Oid"))
 inner join "dbo"."ProductLink" N2 on (N1."ProductLink" = N2."Oid"))
 inner join "dbo"."Technology" N3 on (N2."Technology" = N3."Oid"))
where (N1."GCRecord" is null and (N0."IsPrivate" = 0) and ((N0."HasMarkedAnswers" = 0) or N0."HasMarkedAnswers" is null) and (N3."Name" = N'Discussions'))
order by N1."ModifiedOn" desc
Run Code Online (Sandbox Code Playgroud)

两个查询都是相同的,除了首先选择前10名 ,第二名选择前30名.两个查询都返回相同的结果集 - 6行.但第二个查询比第一个快5倍!我查看了两个查询的实际执行计划,当然,它们有所不同.第二个查询使用索引视图,执行得很好,第一个查询拒绝使用它,而是使用表上的索引.我重复一遍 - 两个查询都是相同的,在同一个表中,在同一个服务器上,它们仅在"顶部"部分中的数字不同.我试图通过更新统计信息,销毁它使用的索引等强制优化器在第一个查询中使用索引视图.无论我如何尝试实际执行,都不要对第一个查询使用索引视图,并始终将其用于第二个查询.

我真的对导致这种行为的原因感兴趣.有什么建议?

更新我不确定它可以帮助而不描述相应的索引和视图,但这是实际的执行计划图表:对于选择前19: 选择前19名:

选择前18名: 选择前18名:

另一个令人困惑的事实是,对于select top 19查询,有时使用索引视图,有时不使用

Chr*_*end 1

我唯一能想到的可能是第一个查询中的优化器得出的结论是,指定标准的选择性不足以使用“更好”的执行计划。

如果您仍在对此进行调查,请查看 TOP 60、90、100... 是否生成第二个执行计划并执行良好。您还可以修改它,看看优化器在这种情况下选择第二个计划的阈值是多少。

还可以尝试不使用 order by 语句的查询,看看这是否会影响查询计划的选择(检查该字段的索引等)

除此之外,您说您不能使用索引提示,因此也许重新编写从 Article 表 (N1) 中选择 top X 并在 where 子句中使用一堆存在语句将为您提供更好的性能。