你能看一下吗http://sqlfiddle.com/#!18/7ad28/8,帮助我理解为什么添加where条件会在seek from scan上带来索引?根据我的(错误的)理解,它不应该有任何区别,因为它是一个更大的条件,应该导致扫描。
我还在下面粘贴有问题的表脚本和查询
CREATE TABLE [dbo].[Mappings]
(
[MappingID] [smallint] NOT NULL IDENTITY(1, 1),
[ProductID] [smallint] NOT NULL,
[CategoryID] [smallint] NOT NULL
)
GO
ALTER TABLE [dbo].[Mappings] ADD CONSTRAINT [pk_Mappings_MappingID] PRIMARY KEY CLUSTERED ([MappingID]) WITH (DATA_COMPRESSION = PAGE) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [nc_Mappings_ProductIDCategoryID] ON [dbo].[Mappings] ([ProductID], [CategoryID]) WITH (DATA_COMPRESSION = PAGE) ON [PRIMARY]
GO
CREATE TABLE [dbo].[CustomerProducts]
(
[CustomerID] [bigint] NOT NULL,
[ProductID] [smallint] NOT NULL,
[SomeDate] [datetimeoffset] (0) NULL,
[SomeAttribute] [bigint] NULL
)
GO
ALTER TABLE [dbo].[CustomerProducts] ADD CONSTRAINT [pk_CustomerProducts_ProductIDCustomerID] PRIMARY KEY CLUSTERED ([ProductID], [CustomerID]) ON [PRIMARY]
GO
--SCAN [tempdb].[dbo].[Mappings].[nc_Mappings_ProductIDCategoryID].(NonClustered)
SELECT b.[SomeDate],
b.[SomeAttribute]
FROM dbo.[Mappings] a
INNER JOIN dbo.CustomerProducts b
ON a.[ProductID] = b.[ProductID]
Where b.CustomerID = 88;
--SEEK [tempdb].[dbo].[Mappings].[nc_Mappings_ProductIDCategoryID].(NonClustered)
SELECT b.[SomeDate],
b.[SomeAttribute]
FROM dbo.[Mappings] a
INNER JOIN dbo.CustomerProducts b
ON a.[ProductID] = b.[ProductID]
AND b.CustomerID = 88
Where a.[ProductID] > 0;
2条答案
按热度按时间qco9c6ql1#
“它不应该有任何区别,因为它是一个更大的条件,应该导致扫描。”
您添加了一个显式 predicate (productid>0),因此SQLServer选择在该值(0)上查找,然后进行范围扫描。要查看这一点,请选择索引seek on mappings,打开properties选项卡,查找seek predicate ,并展开整个结果树。您将在下面看到开始和适用的范围扫描属性。
所以如果你有真实的数据(假设你有1-100的productid),并且有一个where productid>77。您将在b树中查找productID77,然后对非聚集索引的其余部分进行范围扫描。
注意:这将帮助您可视化和理解不同索引操作中内部发生的事情(免责声明:这是我的演示)https://youtu.be/fdd4lw6dfqu?t=748
dbf7pr2w2#
计划如下:
屏幕上的信息以黄色显示
clustered index seek
从表CustomerProducts
. seek predicate 被设置为条件的值[ProductID] > 0
作为连接条件的一部分是完全合理的a.[ProductID] = b.[ProductID]
还有a.[ProductID] > 0
在where子句中。这意味着b.[ProductID] > 0
. 作为ProductID
是聚集索引上的第一列,可以使用任何减少查找的信息。seek操作应该比scan快,因此优化器将尝试这样做。