【发布时间】:2008-10-30 14:11:44
【问题描述】:
显然(我认为),在 BIT 列上创建索引是不必要的。但是,如果您有一个需要搜索的列,其中每个值都可能是唯一的,例如 BlogPost 或 StreetAddress 或其他什么,那么索引似乎是合适的(再次,我认为)。
但是截止点是多少?如果您期望有 10,000 行并且其中将有大约 20 个唯一值,该怎么办。是否应该创建索引?
提前致谢。
【问题讨论】:
显然(我认为),在 BIT 列上创建索引是不必要的。但是,如果您有一个需要搜索的列,其中每个值都可能是唯一的,例如 BlogPost 或 StreetAddress 或其他什么,那么索引似乎是合适的(再次,我认为)。
但是截止点是多少?如果您期望有 10,000 行并且其中将有大约 20 个唯一值,该怎么办。是否应该创建索引?
提前致谢。
【问题讨论】:
对此的最佳答案是分析您的查询并查看索引是否改进了您的查询。回答这个问题的困难在于几乎不可能概括查询优化器的行为。
也就是说,经验法则是,如果您对表的给定查询的选择性为 10% 或更少,那么您很可能会从索引中受益。因此,在您的示例中,如果您的值均匀分布,您可能会从索引中受益。但是,考虑到您的表很小,因此您的性能提升可能可以忽略不计。
这不是一个硬性规定,因为有很多因素可以改变 10% 的数字,包括使用聚集索引或其他索引类型、行的大小、如果某些列不是内联的、查询结构等。
另外请记住,插入带有索引的表会显着降低性能。如果此表经常更新或附加,则索引的速度提升可能会被较慢的插入和更新所抵消。
请参阅 Tablescan vs Index access 上的 MSDN 文章。
编辑:正如其他人指出的那样,如果您正在执行聚合查询,例如计算特定值出现的次数,您的查询可能会受益于索引。如果您经常对特定列进行排序,您也可能会受益。
【讨论】:
詹姆斯一针见血。我将补充一点,根据您使用表的方式,即使是位列也可能受益于索引。例如,如果您需要计算一天中多次出现 1 的行数,那么索引可能会很有用。索引并不总是用于查找单个记录 - 它们也可以用于聚合。
【讨论】:
基数低的索引非常有问题。如果只有几个可能的值,SQL Server 几乎总是索引扫描,无论比例如何。
示例:我有一个带有 State 字段的表,它只接受值“A”、“N”和“R”(用于 Active、New 和 Retired。)通常您会接近一个条件,其中95% 为“R”,4+% 为“A”,少数为“N”。 SELECT WHERE state = 'N' 无论如何都会进行表扫描。
但是 - 有一个新的索引类型称为 Filtered Index,,它最终处理了这种情况。当您想要排除具有 NULL 值的记录时,它也很方便。
【讨论】:
在您建议的列中,有理由为数据创建参考或查找表以避免数据冗余。这将使您的列成为外键,指向新查找表的 PK。
所有外键列都应该被索引。
否则,我会避免在正常情况下在此类列上放置索引。
【讨论】:
没有必要在
BIT列上创建索引。
你会感到惊讶。
我必须为如下查询创建一个涉及位列的索引:
SELECT foo.Name FROM foo WHERE foo.Active = 1
不过,表中有大约 300,000 行。
【讨论】:
我想说这完全取决于表的使用方式和整体系统要求。例如,如果它是大型 JOIN 的一部分,并且父级是一个巨大的报表类型表,那么您肯定需要索引。如果与数据库中的其他表相比它相对较小,并且它被大量插入并且很少读取,那么可能不需要索引。
但是,整个数据库的操作范围与要分配的可用资源是关键的决策因素。这是该表 + 可能的索引在整个系统中与所有其他表及其要求相比的行为方式。如果您不牢记大局,您可能会为了应用任意规则而尝试应用任意规则来杀死整个系统。
【讨论】:
如果您开始遇到查询之间的死锁,通常在 SELECT 和 INSERT/UPDATE 之间,您还应该仔细检查您的索引。选择不当的索引会导致死锁,就像根本没有索引一样。有关更多信息,请参阅this knowledge base 文章。通常,添加索引或修改其包含的列将有助于解决此类死锁。请务必检查受影响查询的查询计划。
【讨论】:
最好的方法之一是在 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
然后验证您的表并创建请求索引。
【讨论】:
这里已经发布了很好的答案......只需添加我的两分钱......执行缺失索引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
【讨论】: