何时创建新的SQL Server索引?

时间:2008-10-30 14:11:44

标签: sql database tsql

显然(methinks),在BIT列上创建索引是不必要的。但是,如果您有一个需要搜索的列,其中每个值都可能是唯一的,例如BlogPostStreetAddress或其他什么,那么索引似乎是合适的(再次,表示)。

但是什么是截止?如果您期望10,000行,并且您将拥有大约20个唯一值,该怎么办?是否应该创建索引?

提前致谢。

9 个答案:

答案 0 :(得分:17)

对此最佳答案是对查询进行概要分析,并查看索引是否可以改进您的查询。回答这个问题的困难在于,几乎不可能概括查询优化器的行为。

也就是说,一个经验法则是,如果您对表上的给定查询的选择性为10%或更低,那么您很可能会从索引中获益。因此,在您的示例中,如果您的值均匀分布,则可能从索引中受益。但是,考虑到你的桌子很小,所以你的性能提升可以忽略不计。

这不是一个硬性规则,因为有很多因素可以改变10%的数量,包括使用聚簇或其他索引类型,行的大小,如果某些列不是内联的,查询结构等等。

另外请记住,插入带索引的表会有显着的性能损失。如果经常更新或附加此表,则可以通过较慢的插入和更新来抵消索引的速度提升。

请参阅Tablescan vs Index access上的MSDN文章。

编辑:正如其他人所指出的,如果您正在执行聚合查询(例如计算特定值出现的次数),您的查询可能会从索引中受益。如果您经常对特定列进行排序,也可能会受益。

答案 1 :(得分:2)

詹姆斯击中了头部的钉子。我只想补充说,根据你使用表的方式,即使是一个列也可能从索引中受益。例如,如果您需要计算一天中多次使用1次的行数,那么索引可能很有用。索引并不总是关于查找单个记录 - 它们也可以用于聚合。

答案 2 :(得分:2)

基数低的索引非常有问题。如果只有几个可能的值,SQL Server几乎总是索引扫描,无论比例是多少。

示例:我有一个带有State字段的表,只接受值“A”,“N”和“R”(对于Active,New和Retired)。通常情况下,您接近一个条件95%为“R”,4 +%为“A”,少数为“N”。 SELECT WHERE state ='N'将进行表扫描,无论如何。

但是 - 有一个名为Filtered Index,的新索引类型,它最终会处理这种情况。当您想要排除具有NULL值的记录时,它也很方便。

答案 3 :(得分:1)

在您建议的列中,有理由为数据创建引用或查找表以避免数据冗余。这将使您的列成为外键,指向新查找表的PK。

所有外键列都应编入索引。

否则,我会避免在正常情况下将索引放在这样的列上。

答案 4 :(得分:1)

  

BIT列上创建索引是不必要的。

你会感到惊讶。

我必须为查询创建一个涉及位列的索引,如:

SELECT foo.Name FROM foo WHERE foo.Active = 1

表中大约有300,000行。

答案 5 :(得分:0)

我想说这一切都取决于表的使用方式和整体系统要求。例如,如果它是一个大型JOIN的一部分而且父级是一个巨大的报告类型表,那么你肯定想要索引。如果它与数据库中的其他表相比相对较小,并且它被大量插入并且很少读取,则可能不需要索引。

但是,整个数据库中的操作范围与要分配的可用资源是关键决策因素。这个表+可能的索引在整个系统中的表现与所有其他表及其要求相比如何。如果你不记住大局,你可以通过试图应用一些任意规则来杀死整个系统,只是为了应用任意规则。

答案 6 :(得分:0)

如果您开始遇到查询之间的死锁,通常在SELECT和INSERT / UPDATE之间,您还应该仔细检查索引。选择不当的索引可能导致死锁,因为根本无法获得索引。有关其他信息,请参阅this knowledge base文章。通常,添加索引或修改其包含的列将有助于解决此类死锁。请务必检查受影响查询的查询计划。

答案 7 :(得分:0)

最好的方法之一是使用SQL Server中的mvp视图 我觉得不要重启你的服务器一周,然后运行这个查询:

USE master; 
Go
SELECT d.database_id,
  d.object_id,
  d.index_handle,
  d.equality_columns,
  d.inequality_columns,
  d.included_columns,
  d.statement AS fully_qualified_object,
  gs.*
FROM   sys.dm_db_missing_index_groups g
JOIN   sys.dm_db_missing_index_group_stats gs ON   gs.group_handle = g.index_group_handle
JOIN   sys.dm_db_missing_index_details d ON   g.index_handle = d.index_handle

Go

SELECT mig.index_group_handle,
  mid.index_handle,
  migs.avg_total_user_cost AS AvgTotalUserCostThatCouldbeReduced,
  migs.avg_user_impact AS AvgPercentageBenefit,
  'CREATE INDEX missing_index_' + CONVERT (varchar, mig.index_group_handle)
  + '_' + CONVERT (varchar, mid.index_handle)
  + ' 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
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
Order By migs.avg_user_impact Desc

然后验证您的表并创建requerd索引。

答案 8 :(得分:0)

这里已经发布了很好的答案......只需添加我的两分钱......执行缺失的索引DMV并查看您提到的表是否被列为创建新索引的候选者并查看索引的定义。

来自Are you using SQL's Missing Index DMVs?

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