索引列顺序和扫描而不是查找

时间:2020-03-17 07:36:07

标签: sql-server indexing sql-server-2016 sql-execution-plan

请考虑Customer数据库中的Northwind表:

我在3列上添加了索引:

CREATE NONCLUSTERED INDEX [idx_1] ON [dbo].[Customers]
    ([CompanyName] ASC, [City] ASC, [Country] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

我测试了这些查询:

1) SELECT CompanyName,city,country FROM [Northwind].[dbo].[Customers] where CompanyName='a' and city='b' and country='c'

2) SELECT CompanyName,city,country FROM [Northwind].[dbo].[Customers] where country='c' and CompanyName='a' and city='b'

3) SELECT CompanyName,city,country FROM [Northwind].[dbo].[Customers] where CompanyName='a' and country='c'

4) SELECT CompanyName,city,country FROM [Northwind].[dbo].[Customers] where CompanyName='a' and city='b'

以上所有查询均使用Index Seek

这些谓词是否存在

A)如果我的索引包含N列,则这些N列中与其值相等的所有排列都使用Index Seek,因此列的顺序为当所有列都参与Index子句时,Where无关紧要。

B)如果我的索引包含N列(例如:Col1, Col2, Col3,...) then all these combinations in在哪里clause use寻找索引:

B-1) Col1, Col2,
B-2) Col1, Col2, Col3
B-3) Col1, Col3, Col4
B-4) Col1, Col4, Col7

因此,Col1对于使用Index Seek很重要。

请考虑以下查询:

5) SELECT CompanyName,city,country, PostalCode FROM [Northwind].[dbo].[Customers] where CompanyName='a' and city='b' and country='c'

C)我在选择列表中添加了PostalCode,为什么Index Seek会转换为Index Scan?为什么Seek未转换为Seek + Key Lookup

1 个答案:

答案 0 :(得分:1)

1)列顺序确实很重要,因为索引键是使用指定的列顺序构造的。因此,只有在您的谓词中包含CompanyName列时(如所有WHERE子句中一样),才能有效地进行索引查找(而不是扫描)。谓词中列的顺序无关紧要-查询优化程序将确定是否指定了必要的列才能执行查找。

2)同样,Col1必须包含在内,因为它是为索引指定的第一列,因此形成了索引键的开头。

3)添加PostalCode意味着索引不再覆盖提供查询所需的所有列。然后由查询优化器来评估索引查找或索引扫描是否更有效。这将取决于许多因素,但是一个重要的因素将是谓词将返回它估计的行数,以及相对于扫描表(群集)的开销,必须执行多少次(昂贵的)键查找。指数)。显然已经确定,在这种情况下,对聚集索引的扫描会更有效。