Sql server 为什么SQL Server有时会选择索引扫描而不是书签查找?

Sql server 为什么SQL Server有时会选择索引扫描而不是书签查找?,sql-server,sql-server-2008-r2,Sql Server,Sql Server 2008 R2,我们有一个简单的表格,如下所示: OrderID primary key / clustered index CustomerID foreign key / single-column non-clustered index [a bunch more columns] SELECT [a bunch of columns] FROM Orders WHERE CustomerID = 1234 然后,我们有这样一个查询: OrderID primary key / clustered i

我们有一个简单的表格,如下所示:

OrderID primary key / clustered index
CustomerID foreign key / single-column non-clustered index
[a bunch more columns]
SELECT [a bunch of columns]
FROM Orders
WHERE CustomerID = 1234
然后,我们有这样一个查询:

OrderID primary key / clustered index
CustomerID foreign key / single-column non-clustered index
[a bunch more columns]
SELECT [a bunch of columns]
FROM Orders
WHERE CustomerID = 1234
我们发现,有时SQL Server 2008 R2会在非聚集索引上进行查找,然后在聚集索引上进行书签查找(我们喜欢这样,它非常快)

但在其他看似随机的情况下,SQL Server会对聚集索引进行扫描(速度非常慢,会让我们的应用程序陷入爬行状态,而且似乎在一天中最繁忙的时间进行扫描)

我知道我们可以(a)使用索引提示,或者(b)增强我们的非聚集索引,以便它覆盖我们选择的大量列。但是(a)将逻辑与物理联系起来,关于(b),我已经读到索引不应该覆盖太多的列


我首先想听听SQL Server为什么要这么做。此外,任何建议都将不胜感激。谢谢

您应该将索引设为a,这样就不需要进行书签查找。这是一个潜在的昂贵操作,可能会导致查询优化程序忽略您的索引

如果您使用的是SQL Server 2005或更高版本,则可以将其添加为,否则必须将其添加为其他键列


覆盖索引总是比非覆盖索引性能更好,尤其是对于非选择性查询。

CustomerID的选择性将在查询优化人员的决策中发挥一定作用。一方面,如果它是唯一的,那么相等操作最多只能产生一个结果,因此几乎可以保证查找/查找操作。另一方面,如果可能有数百或数千条记录与CustomerID的值相匹配,则聚集索引扫描可能更具吸引力

你会惊讶地发现,为了排除扫描,过滤器必须具有多么高的选择性。我找不到我最初从中提取这个数字的文章,但是如果CustomerID 1234只匹配表中4%的记录,那么对聚集索引的扫描可能会更有效,或者至少在优化者看来是这样的(这并不是100%正确)

CustomerID上非聚集索引上保存的统计信息导致优化程序根据选择性标准在搜索/扫描之间切换,这听起来至少是合理的

通过引入连接或存在操作,您可以引导优化人员使用索引:

-- Be aware: this approach is untested
select o.*
  from Orders o
       inner join Customers c on o.CustomerID = c.CustomerID
 where c.CustomerID = 1234;
或:

还要注意,使用这种
EXISTS
方法,如果在两个表中的“join”谓词(在本例中是CustomerID字段)上没有索引,那么最终将出现一个嵌套循环,速度非常慢。使用内部联接似乎安全得多,但
EXISTS
方法有时也有它的位置,它可以利用索引


这些只是建议,;我不能说它们是否有效。只是尝试一下,或者由常驻专家确认或拒绝。

+1好的建议-如果可以创建一个索引所涵盖的查询,那么这些随机情况下也可以使用单个
CustomerID进行查询,或者您一次查询多行?书签查找是一项非常昂贵的操作,因此扫描速度加快的临界点非常低——远低于大多数人的预期。您帮助我认识到,我们的问题可能是,一个客户可以返回多个订单,这使得查询不具有选择性。因此,我认为我们将创建一个覆盖索引,覆盖返回的12个左右字段。然而(对我来说)这样做的一个缺点是我们可能会在查询中添加一个字段,而忘记扩展覆盖索引。我想我们需要用勿忘我的方式来评论我们的提问。