索引列顺序和扫描而不是查找
Index columns order and Scan instead of seek
请考虑 Northwind
数据库中的 Customer
table:
我在 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
因此,当所有列都参与 Where
子句时,Index
中的列顺序并不重要。
B) 如果我的索引有 N
列(例如:Col1, Col2, Col3,...) then all these combinations in
Whereclause use
Index Seek`:
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) 我在Select列表中添加了PostalCode
,为什么Index Seek
转换为Index Scan
?为什么 Seek
没有转换为 Seek + Key Lookup
?
1) 列顺序很重要,因为索引键是使用指定的列顺序构造的。因此,只有在谓词中包含 CompanyName
列(就像在所有 WHERE
子句中一样),才能有效地进行索引查找(而不是扫描)。列在谓词中的顺序无关紧要 - 查询优化器将确定是否指定了必要的列以执行查找。
2) 同样,需要包含 Col1
,因为这是为索引指定的第一列,因此构成了索引键的开头。
3) 添加 PostalCode
意味着索引不再涵盖提供查询所需的所有列。然后由查询优化器来评估索引查找或索引扫描是否更有效。这将取决于许多因素,但一个重要的因素是它估计谓词将返回多少行,因此相对于扫描 table(聚簇索引)。很明显,在这种情况下,聚簇索引的扫描效率更高。
请考虑 Northwind
数据库中的 Customer
table:
我在 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
因此,当所有列都参与 Where
子句时,Index
中的列顺序并不重要。
B) 如果我的索引有 N
列(例如:Col1, Col2, Col3,...) then all these combinations in
Whereclause use
Index Seek`:
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) 我在Select列表中添加了PostalCode
,为什么Index Seek
转换为Index Scan
?为什么 Seek
没有转换为 Seek + Key Lookup
?
1) 列顺序很重要,因为索引键是使用指定的列顺序构造的。因此,只有在谓词中包含 CompanyName
列(就像在所有 WHERE
子句中一样),才能有效地进行索引查找(而不是扫描)。列在谓词中的顺序无关紧要 - 查询优化器将确定是否指定了必要的列以执行查找。
2) 同样,需要包含 Col1
,因为这是为索引指定的第一列,因此构成了索引键的开头。
3) 添加 PostalCode
意味着索引不再涵盖提供查询所需的所有列。然后由查询优化器来评估索引查找或索引扫描是否更有效。这将取决于许多因素,但一个重要的因素是它估计谓词将返回多少行,因此相对于扫描 table(聚簇索引)。很明显,在这种情况下,聚簇索引的扫描效率更高。