1

我们有一个视图,用于通过聚集索引在表中查找记录。该视图在 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] 有 400 万条记录,[a] 的大多数值为 null
  • 我现在无法掌握生成计划的初始查询
  • 这些查询是通过 Coldfusion 运行的,但此时我对任何在 SQL Server 中独立看到过的人感兴趣
4

1 回答 1

3

这似乎是完全错误的,总是。

您可能对第一条编程规则感兴趣。

因此,按照上面的示例,尽管 tableB 上存在列 [a] 的索引,但计划改为扫描具有列 [z] 的聚集索引。

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

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

当您执行聚集索引扫描时,您根据定义查找所有列。这意味着不需要书签查找。

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

您可以通过使用with (index(IX_YourIndex))query hint强制来测试您的情况。

于 2013-01-11T12:12:44.860 回答