SQL Server 2005缓存了一个永远无法工作的执行计划

时间:2013-01-11 11:39:57

标签: sql-server sql-server-2005 sql-execution-plan

我们有一个视图,用于通过聚集索引查找表中的记录。该视图在select语句中还有一些子查询,它们通过聚簇索引在两个大表中查找数据。

为了大大简化它会是这样的:

SELECT a,
(SELECT b FROM tableB where tableB.a=tableA.a) as b
(SELECT c FROM tableC where tableC.a=tableA.a) as c
FROM tableA

对[tableB]的大多数查找都正确地在[tableB]上使用非聚集索引并且工作效率非常高。但是,SQL Server在生成执行计划时,偶尔会在[tableB]上使用不包含传递值的索引。因此,按照上面的示例,虽然tableB上存在列[a]的索引,但计划会扫描具有列[z]的聚簇索引。使用SQL自己的语言,计划的“谓词与对象无关”。我不明白为什么这会变得实用。因此,当SQL执行此操作时,它必须扫描索引中的每个记录,因为它永远不会存在,最多需要30秒。总而言之,这似乎是完全错误的。

之前有没有人看到这个,执行计划做了一些看起来永远不会正确的事情?我还是要重写查询,所以我关心的不是查询的结构,而是关于为什么SQL会错误的结果。

我知道有时SQL Server可以选择一次工作的计划,随着数据集的变化它会变得低效,但在这种情况下它永远不会起作用。

更多信息

  • [tableB]有4百万条记录,[a]的大多数值为空
  • 我现在无法掌握生成计划的初始查询
  • 这些查询是通过Coldfusion运行的,但此时我对在SQL Server中独立看到此内容的任何人感兴趣

1 个答案:

答案 0 :(得分:3)

  

这似乎是完全错误的。

您可能对First Rule of Programming感兴趣。

  

所以,按照上面的例子,尽管列[a]的索引   如果存在于tableB上,则计划会扫描聚簇索引   有列[z]。

聚簇索引始终包含所有行。它可能由z排序,但它仍将包含叶级别的所有其他列。

SQL Server有时更喜欢对索引搜索进行聚簇扫描的原因是这样的。当您执行索引查找时,必须通过对聚簇索引的书签查找来跟进它,以检索不在索引中的列。

执行聚簇索引扫描时,您可以按定义查找所有列。这意味着不需要书签查找。

当SQL Server需要很多行时,它会尝试避免书签查找。这是一个经过时间考验的选择。非聚集索引搜索通常会被聚集索引扫描打败。

您可以使用with (index(IX_YourIndex)) query hint强制测试此案例。