我们有一个简单的表格,如:
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正在做它正在做的事情。此外,任何建议将是最受欢迎的。谢谢!
答案 0 :(得分:4)
您应该将索引设为covered index,以便不需要书签查找。这是可能导致查询优化器忽略您的索引的潜在昂贵操作。
如果您使用的是SQL Server 2005或更高版本,则可以将它们添加为included columns,否则您必须将它们添加为其他键列。
覆盖索引总是比非覆盖索引执行得更好,特别是对于非选择性查询。
答案 1 :(得分:4)
CustomerID
的选择性将在查询优化器的决策中发挥作用。如果一方面它是唯一的,那么相等操作最多只能产生一个结果,所以几乎可以保证SEEK / LOOKUP操作。另一方面,如果可能有数百或数千条记录与CustomerID的值匹配,那么聚簇索引扫描可能看起来更具吸引力。
您会惊讶于过滤器必须选择何种方式来排除扫描。我找不到我最初从这个数字中提取的文章,但是如果CustomerID 1234与表中的记录只有4%相匹配,那么对聚簇索引的扫描可能会更有效,或者至少看起来如此优化器(100%的时间都不能正确)。
至少可以理解,在CustomerID上的非聚集索引上保留的统计信息会导致优化器根据选择标准在搜索/扫描之间切换。
您可以通过引入JOIN或EXISTS操作来诱使优化器使用索引:
-- Be aware: this approach is untested
select o.*
from Orders o
inner join Customers c on o.CustomerID = c.CustomerID
where c.CustomerID = 1234;
或者:
-- Be aware: this approach is untested
select o.*
from Orders o
where exists (select 1
from Customers c
where c.CustomerID = 1234 and
o.CustomerID = c.CustomerID);
另请注意,使用此EXISTS
方法,如果两个表中的“join”谓词(在本例中为CustomerID字段)没有索引,则你最终会得到一个痛苦慢的嵌套循环。使用内连接似乎更安全,但EXISTS
方法有时可以利用索引。
这些只是建议;我不能说他们是否会有效。只是尝试一下,或让驻地专家确认或否认。