定义索引:哪些列和性能影响?

时间:2009-12-23 18:07:30

标签: sql sql-server tsql indexing

我知道如何使用索引(clustured和non clustured) 但什么时候我应该在我的表中使用非clustured索引。 应该有哪些场景,以便使我的列不受限制。 我已经完成了msdn指南,但仍然有点混乱。

我应该只将唯一列作为NC,还是将其他列作为NC。

如果我用NC索引重载我的表,那么它也会降低我的性能吗?

我是否应该在外键列上使用复合非C索引。

我知道主键应该是Clustured,唯一键应该是NC但是外键呢。

6 个答案:

答案 0 :(得分:8)

聚集索引定义了您的表的物理结构(在某种程度上) - 例如它定义了数据的排序顺序。想想电话簿,它被(LastName,FirstName)“聚集” - 至少在大多数国家都是如此。

每个表只能获得一个聚簇索引 - 所以明智地选择它!根据{{​​3}}的福音,聚类键应该是窄的,稳定的(永不改变),唯一的(是的!),理想的是不断增加。

它应该很窄,因为聚类键将被添加到每个非聚集索引的每个条目中 - 毕竟,聚类键是用于最终查找实际数据的值。

它应该是稳定的,因为不断更新大量索引值是一件代价高昂的事情 - 特别是因为集群密钥也必须在所有非聚集索引中更新。

它需要是唯一的,因为它再次 - 它最终是用于定位实际数据的价值。如果您选择的列不能保证唯一,SQL Server将通过向其添加4字节值来“统一”您的群集密钥 - 这不是一件好事。

理想情况下,群集密钥应该不断增加,因为这会导致页面和索引碎片最少,因此最适合性能。

群集密钥的理想候选者是INT(或BIGINT)IDENTITY - 它理想地满足所有这些要求。

对于非聚集索引 - 明智地使用和选择它们!我只能给你一条通用规则:作为外键一部分的所有列(引用另一个表)应该在索引中 - SQL Server不会(与流行的看法和许多神话相反)放置这样的索引自动 - 永远不会,永远不会。

除此之外 - 你需要观察你的系统,看看你有什么样的查询 - 在WHERE或SORT子句中出现的所有列都是可能被索引的候选者 - 但是过多的索引并不是一件好事任一....

答案 1 :(得分:4)

每个表只能有一个聚簇索引。它不一定是主键,但在大多数情况下它将是。

除此之外 - 它实际上取决于查询& tipping point for what indexes will be used。但定义索引也意味着会对DML产生影响 - 插入,更新和更新删除会略微影响性能。

  

我应该在外键列上使用复合非聚簇索引吗?

无论列是什么,优化器确定要使用哪个索引(群集或其他)都很重要。

答案 2 :(得分:2)

是的,您可以使用过多索引重载表。通常,每个附加索引都会在索引维护方面花费执行时间。大量更新的表通常应该有更少的索引。

另一个广泛的规则(来自Richard Campbell,在RunAs Radio和DotNetRocks上)是一些广泛的索引将比大量的窄索引表现更好。广泛的索引将涵盖更广泛的查询,并且查询优化器可以进行更少的调查。请记住,查询优化器的运行时间有限。

调查SQL Server Profiler。那里有工具(曾经是独立的,但它们已经改变了,我最近没有使用它们)。他们可以分析工作负载并制定索引建议。这些将是比“直观地”选择的索引更好的选择。

答案 3 :(得分:0)

如果您的查询引用了索引中不存在的列,则SQL Server引擎必须执行表查找以从实际表中获取未包含的列。

如果经常运行这些查询,则应通过在索引中包含所有引用的列来创建“覆盖”查询的非聚簇索引。这应包括任何非唯一列。

向表中添加索引总是会降低写入性能,因为每次更新表时都必须更新索引。

答案 4 :(得分:0)

您正在查找哪些字段?搜索?等等。 确定运行查询时使用的字段(WHERE子句) 他们可能是很好的候选人。

例如,想一下图书馆。图书目录具有ISBN编号的聚簇索引和发布年份的非聚集索引等

很有帮助我的是Bart Duncan很久以前发布的东西。 他值得赞扬。

这篇文章的标题是“你使用SQL的缺失索引DMV吗?”。查找并运行此查询:

SELECT 

  migs.avg_total_user_cost * (migs.avg_user_impact / 100.0) * (migs.user_seeks + migs.user_scans) AS improvement_measure, 

  'CREATE INDEX [missing_index_' + CONVERT (varchar, mig.index_group_handle) + '_' + CONVERT (varchar, mid.index_handle) 

  + '_' + LEFT (PARSENAME(mid.statement, 1), 32) + ']'

  + ' ON ' + mid.statement 

  + ' (' + 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, '')

  + ')' 

  + ISNULL (' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement, 

  migs.*, mid.database_id, mid.[object_id]

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

它不是最终的解决方案,但它可以帮助您确定一些索引。 以及文章的链接:http://blogs.msdn.com/bartd/archive/2007/07/19/are-you-using-sql-s-missing-index-dmvs.aspx。默认情况下,在SQL Server中创建PK时,默认情况下是聚簇索引,但不一定是这样,但通常是。

答案 5 :(得分:0)

如果您是否应该创建聚簇索引取决于您的工作负载(通常由命中表的SELECT语句的数量和种类占主导地位)

聚簇索引将强制行的磁盘存储顺序取决于聚簇索引值。 (因此,每个表只能有1个聚簇索引,因为行只存储在磁盘上一次)如果大多数查询总是要求一组相关行,这是有意义的。

示例:假设您正在存储CustomerOrders,并且您经常想知道特定时间段内CustomerOrders的数量(无论客户如何)。在这种情况下,使用OrderDate作为第一列创建集群索引可能很有用。另一方面,如果您经常查找具有相同CustomerId的所有CustomerOrders,则将CustomerId作为聚簇索引中的第一列更有意义。

聚簇索引的缺点不在于de clustered索引本身,而是在二级索引上:二级索引本身不是聚类的(根据定义,因为行只能存储一次,并按聚簇索引的顺序存储),它们的索引条目指向聚集索引的索引条目。因此,要通过辅助索引检索行,需要2个读取操作:其中一个辅助索引,然后是指向它的聚簇索引之一。