我的问题是,如果非聚集索引索引的列多于查询使用的列,这是否会导致查询执行速度比完全匹配查询的索引慢?
不,拥有更多列不会减慢使用索引中前 1、2、n 列的查询的查询时间。话虽如此,如果您的内存有限,则加载到内存中的索引可能会将其他内容推出内存并减慢查询速度,但如果您有足够的内存,这应该不是问题。
随着不同查询数量的增加,WHERE 子句中使用的列的排列数量也会增加。我不确定在具有少量列的多个索引(每个查询一个)与在更多列上的更少索引之间进行权衡。
您应该首先将最常查询的唯一字段添加到索引中。
具有多列的较少索引可能无法满足您的需求。
例如,如果您有一个包含以下列的索引:
按此顺序,针对 ColumnA、ColumnB、ColumnC、ColumnD... 进行过滤的查询将使用索引,但如果您只是针对 ColumnE 或 ColumnF 进行查询,则不会使用索引。
如果您在一个表上有六个索引,每个索引只有一列,请采用不同的方法
- Index1 - 列A
- Index2 - ColumnB
- Index3 - ColumnC
- Index4 - ColumnD
- Index5 - ColumnE
- Index6 - ColumnF
在这种情况下,这 6 个索引中只有一个会用于任何查询。
此外,如果您的索引包含的值不是很有选择性,那么它可能对您没有帮助。例如,如果您有一个名为 GENDER 的列,其中可能包含以下值(男性、女性和未知),那么在索引中包含该列可能不会帮助您。当查询运行时,SQL Server 可能会确定它们的列选择性不够,只是假设全表扫描会更快。
有很多方法可以找出您的查询正在使用哪些索引,但我使用的一种方法是查看从未使用过的索引。在您的数据库中运行以下查询,并找出您认为正在使用的索引是否真的被使用了。
SELECT iv.table_name,
i.name AS index_name,
iv.seeks + iv.scans + iv.lookups AS total_accesses,
iv.seeks,
iv.scans,
iv.lookups,
t.indextype,
t.indexsizemb
FROM (SELECT i.object_id,
Object_name(i.object_id) AS table_name,
i.index_id,
SUM(i.user_seeks) AS seeks,
SUM(i.user_scans) AS scans,
SUM(i.user_lookups) AS lookups
FROM sys.tables t
INNER JOIN sys.dm_db_index_usage_stats i
ON t.object_id = i.object_id
GROUP BY i.object_id,
i.index_id) AS iv
INNER JOIN sys.indexes i
ON iv.object_id = i.object_id
AND iv.index_id = i.index_id
INNER JOIN (SELECT sys_schemas.name AS schemaname,
sys_objects.name AS tablename,
sys_indexes.name AS indexname ,
sys_indexes.type_desc AS indextype ,
CAST(partition_stats.used_page_count * 8 / 1024.00 AS DECIMAL(10, 3)) AS indexsizemb
FROM sys.dm_db_partition_stats partition_stats
INNER JOIN sys.indexes sys_indexes
ON partition_stats.[object_id] = sys_indexes.[object_id]
AND partition_stats.index_id = sys_indexes.index_id
AND sys_indexes.type_desc <> 'HEAP'
INNER JOIN sys.objects sys_objects
ON sys_objects.[object_id] = partition_stats.[object_id]
INNER JOIN sys.schemas sys_schemas
ON sys_objects.[schema_id] = sys_schemas.[schema_id]
AND sys_schemas.name <> 'SYS') AS t
ON t.indexname = i.name
AND t.tablename = iv.table_name
--WHERE t.IndexSizeMB > 200
WHERE iv.seeks + iv.scans + iv.lookups = 0
ORDER BY total_accesses ASC;
我通常会跟踪从未使用过的索引,或者在 SQL Server 重新启动后几个月未使用过的索引,并确定是否应该删除它们。有时过多的索引会减慢 SQL Server 找出运行查询的最佳路径的速度,而删除未使用的索引可以加快该过程。
我希望这有助于理解您的索引。