我发现以下SQL旨在帮助识别缺失的索引。我想更好地理解输出。
SELECT migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) AS ExpectedImprovement
, DB_NAME(mid.database_id) AS DBName
, mid.[object_id] AS ObjectID
, mid.statement AS FullyQualifiedObjectName
, ISNULL (mid.equality_columns,'') +
CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN
','
ELSE
''
END +
ISNULL (mid.inequality_columns, '') AS IndexColumns
, ISNULL (mid.included_columns, '') AS IncludeColumns
, migs.user_seeks
, migs.user_scans
, migs.last_user_seek
, migs.last_user_scan
FROM sys.dm_db_missing_index_groups mig
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle
WHERE migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) > 10
ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC
其中一个返回的列是“Include Columns”。
我想知道这是否意味着所提到的列名应该添加到索引中的列列表中,或者是否有其他功能可以返回那些可能是高访问列值而不将它们添加到索引本身。 (也许我想象听到这样的功能,或者可能是另一个供应商的数据库)
输出是否只是建议索引中的列列表按“包含列”返回值中提到的列进行扩展?我对输出做出反应,建议我在索引中添加15个字段,这对我来说似乎有点过分了。
答案 0 :(得分:2)
非聚集索引既包含已编制索引的列的列表,也包含“包含”用于快速参考的列的列表。
例如,假设您有一个包含100列的表,但您几乎只能查询其中的5个,这取决于日期。 e.g。
select col1, col2, col3, col4, YourDate from YourTable where YourDate = '???'
如果仅为日期列编制索引,则必须执行所谓的RowID查找(或书签查找)。您将有效地找到所需的行集,但是您需要返回到物理表以获取要选择的其他4列(col1-col4)。
如果您使用包含的列列表创建索引,那么这些列将完全存储在索引中。
create nonclustered index ix_YourTable on YourTable (
YourDate)
include (
col1, col2, col3, col4)
现在你不回到表中获取col1-4,你直接从索引中读取它们。显然,这会增加该索引所需的存储量。
如果频繁查询更改为
,您还应该知道select col1, col2, col3, col4, col5, YourDate from YourTable where YourDate = '???'
您仍将使用索引,但您将执行RID查找以获取col5的数据。您需要将col5添加到索引的包含列表中,以便有效地引用它。
希望有所帮助!
答案 1 :(得分:1)
SQLServers允许您“包含”非键列(请参阅详细信息here)。索引中键列和非键列之间的主要区别在于,非键列仅存储在索引的叶级中,而不是存储在所有级别的键列。
我不建议按照你的脚本输出建议(你的脚本很好,不要误解我),即你真的不必创建所有建议的索引并包含它想要的所有列来自你根据我的经验,SQLServer希望您使所有查询都具有覆盖索引,这可能会影响更新/插入的性能并增加数据库大小。