【问题标题】:How do I know if I should create an Non clustered Index on a Clustered Index or on a heap?我如何知道是否应该在聚集索引或堆上创建非聚集索引?
【发布时间】:2014-10-15 12:07:22
【问题描述】:
我有一个包含一些表的数据库,没有表定义了非聚集索引。使用这个数据库的大型应用程序很慢(因为行数接近一百万)。我想通过添加索引来优化数据库获取操作。当我阅读索引时,我遇到了索引名称,例如:
- 聚集索引
- 聚集索引上的非聚集索引
- 堆上的非聚集索引
此外,只需要在某些列上创建索引。我将如何在表中识别需要创建哪种索引以及跨哪些列?
P.S. 运行查询时的执行计划告诉在所有列上创建 NCI。我可以盲目地按照 SQL Server 的建议创建索引吗?
【问题讨论】:
标签:
sql-server
sql-server-2008-r2
database-performance
【解决方案1】:
聚集索引是一种索引,它定义了表中数据的存储方式(更准确地说,数据的排序方式)。这就是为什么应该非常小心地选择聚集索引列的原因(顺序插入的数据是原始的,否则随着时间的推移您会遇到碎片和性能问题,例如,整数“身份”列是一个不错的选择)。
我发现在永久表上始终拥有聚集索引是一种很好的做法。
没有聚集索引的表是堆,因为数据没有以特定方式排序(将添加到文件末尾),因此数据更难检索。使用没有索引的堆唯一的改进是数据插入会更快。
非聚集索引是一个单独的文件,有助于加快对所选列的查询(它将存储索引数据的值及其对主文件中位置的引用)。随着表中的数据变得越来越重要,拥有这些单独的文件可以显着提高查询的性能,因为 db 引擎不必扫描整个表以查找您要查找的数据,而只需查找要在索引文件中检索的行的位置(其中包含您选择的列的有序数据)。
添加索引将加快您的选择查询,但会减慢写入操作,因为必须更新索引。 所以,不要在太多列上创建太多索引!
【解决方案2】:
有两种类型的表:堆表(没有聚集索引)和聚集表(有)。每一个都可以有任意数量的非聚集索引。
什么时候使用堆表?实际上,仅在一种情况下:当您进行并行批量导入时。此特定场景要求表没有聚集索引。在所有其他情况下,堆表的性能比具有聚集索引的表要差——不过,不要相信我的话:微软有一个article on this,虽然过时了,但仍然相关。换句话说,对于大多数实际的数据库工作,您可以忽略堆表作为好奇心。
您在什么基础上创建聚集索引?理想情况下,在具有不断增加(或减少)并且在更新中没有更改的值的列上。为什么?因为这具有最少的更新开销,因为不需要移动数据。由于这两个要求,IDENTITY 列形式的代理键很受欢迎,因为它们巧妙地满足了它们。不过,这当然不是唯一可能的选择:在不断增加的时间戳上建立索引也很流行(例如,在大数据仓库中)。
有了这个(大部分)问题,您如何决定要索引哪些其他列?现在这是一个很好的问题,但我觉得没有资格在这里回答所有的荣耀。这些年来,我自己在索引设计方面积累了很多经验,但我不知道我可以推荐哪些具体的书籍或文章(这并不是说它们不存在,我希望其他人也能附和)与建议)。值得一提的是,微软自己有written a guide here,相当深入(也许是太多了),但我自己并没有仔细阅读。
您可以盲目地按照查询优化器的建议创建索引吗?如果你的意思是“我应该”,那么答案几乎肯定是否定的。查询优化器非常渴望建议和所有可以加速查询的可能索引,但这并不意味着它们都应该被创建——每个索引都会增加在表上执行插入和更新的开销。如果您遵循优化器的建议,您最终可能会得到涵盖所有可能的列组合的索引,这对于任何不是SELECT 查询的东西来说都是非常糟糕的。话虽如此,创建过多的索引几乎总是没有创建索引那么糟糕,因为对于大多数涉及超过 10000 行的表的查询来说,这会很快降低性能。
我可以写关于这个主题的书,但我没有时间或(我担心)技能。我希望这至少能让你开始。