我有一个如下所示的查询:
--Updated To remove Distinct per Aaron Bertrand's suggestion in the comments
SELECT TOP 100 ord.OrderId
FROM Customer cust
JOIN CustomerOrder ord
ON ord.CustomerId = cust.CustomerId
WHERE cust.FirstName LIKE (@firstName + '%')
ORDER BY ord.CreatedWhen DESC
我有一个这样的索引:
CREATE NONCLUSTERED INDEX [IX_MyIndex] ON CustomerOrder
(
OrderId DESC,
CustomerId DESC,
CreatedWhen Desc
)
GO
当我运行查询时,会使用索引,但它是索引扫描。它给出了这个信息:
PROBE([Bitmap1011],[MyDatabase].[order].[CustomerOrder].[OrderId] as [ord].[OrderId],N'[IN ROW]')
输出列表由 OrderId 和 CreatedWhen 组成。
这个 PROBE 在做什么,为什么我没有进行索引搜索?
更新:
Customer 表上的 FirstName 列确实有一个在 IndexSeek 中使用的索引。
CREATE NONCLUSTERED INDEX [IX_Customer_FirstName] ON Customer
(
[FirstName] ASC
)
GO
最佳答案
使用索引扫描的原因是因为您的 WHERE 子句谓词基于 CustomerId,但它在非聚集索引 [IX_MyIndex] 的列列表中显示为 SECOND 列.
如果您希望执行索引搜索,您需要在 CustomerId 列上指定一个新的非聚集索引。
这基本上是一个很好的做法 - 为 OrderId 和 CustomerId 设置两个单独的 NC 索引。因此,当您连接 Customer 和 CustomerOrder 表时,它将使用 NC 索引作为 CustomerId,而当您连接 Order 和 CustomerOrder 表时,它将使用 NC 索引作为 OrderId。
引用这个article阅读更多关于多列非聚集索引(您目前拥有的)和多个非聚集索引(我建议使用的)之间的区别。
[更新]
但是创建单独的非聚集索引不足以每次都进行索引查找。这将取决于在查询中选择的列,以及正在读取的数据的大小——基于此,查询优化器将相应地决定是使用 Index Seek 还是 Index Scan。参见 this answer获取更多信息。
[2021 年 2 月 8 日更新]
在较高级别,所讨论的 PROBE 函数实质上会尝试验证 CustomerOrder.OrderId 列值是否存在于 Customer 表中。这是通过使用位图和哈希键在内部实现的,您可以阅读有关它的详细信息 here .
请注意,PROBE 并非特定于索引扫描或索引查找。它只是一个函数,用于验证连接中两个表之间的匹配(基于特定的散列键列)。
关于sql-server - 使用 PROBE 代替索引查找进行索引扫描,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26164447/