索引中的列顺序有多重要?

问题描述 投票:162回答:5

我听说您应该在索引声明的开头放置最有选择性的列。示例:

CREATE NONCLUSTERED INDEX MyINDX on Table1
(
   MostSelective,
   SecondMost,
   Least
)

首先,我说的是正确的吗?如果是这样,我是否可能会通过重新排列索引中的列顺序来看到性能上的巨大差异,还是更多的“不错的做法”?

我问的原因是,通过DTA进行查询后,建议我创建一个索引,其中几乎所有列都与现有索引相同,只是顺序不同。我正在考虑只是将缺少的列添加到现有索引中,并称之为良好。有想法吗?

sql sql-server sql-server-2005 tsql indexing
5个回答
186
投票

看这样的索引:

Cols
  1   2   3
-------------
|   | 1 |   |
| A |---|   |
|   | 2 |   |
|---|---|   |
|   |   |   |
|   | 1 | 9 |
| B |   |   |
|   |---|   |
|   | 2 |   |
|   |---|   |
|   | 3 |   |
|---|---|   |

请参阅第一列限制比第一列限制消除更多的结果?如果您想象必须如何遍历索引,第1列然后第2列,等等,会更容易。。。您会发现,第一遍中大部分结果的丢失使第二步快得多。

[另一种情况,如果您查询第3列,则优化器甚至不会使用索引,因为它对缩小结果集完全没有帮助。 无论何时您在查询中,在进行下一步之前,缩小要处理的结果数量就意味着可以提高性能。

由于索引也是以这种方式存储的,因此在查询第一列时,不会在索引上回溯以找到第一列。

总之:不,这不是为了展示,而是有真正的性能优势。


120
投票

列的顺序很关键。现在哪个顺序正确,取决于您要查询的顺序。索引可用于执行精确搜索或范围扫描。精确查找是指指定索引中所有列的值,并且查询恰好位于该行所关注的位置。对于查找,列的顺序无关紧要。范围扫描是仅指定一些列的情况,在这种情况下,顺序变得很重要。只有指定了最左列,然后指定了下一个最左列,SQL Server才可以将索引用于范围扫描。如果在(A,B,C)上有索引,则可以将其用于A=@aA=@a AND B=@b的范围扫描,但是对于B=@bC=@cB=@b AND C=@cnotA=@a AND C=@c是混合的情况,例如A=@a部分将使用索引,但C=@c不使用索引(查询将扫描所有B值以获取A=@a,不会“跳到” C=@c) 。其他数据库系统具有所谓的“跳过扫描”运算符,当未指定外部列时,该运算符可以利用索引中的内部列。

掌握了这些知识之后,您可以再次查看索引定义。仅当指定(MostSelective, SecondMost, Least)列时,MostSelective上的索引才有效。但是,最有选择性的是,内部列的相关性将迅速降低。很多时候,您会发现在(MostSelective) include (SecondMost, Least)(MostSelective, SecondMost) include (Least)上有更好的索引。由于内部列的相关性较低,因此将低选择性列放置在索引中的此类正确位置上只会使它们产生寻找噪音,因此将它们移出中间页并仅将它们保留在叶子页上是有意义的,因为查询覆盖率的目的。换句话说,将它们移动到INCLUDE。随着Least列大小的增加,这一点变得更加重要。想法是,该索引只能使将MostSelective指定为精确值或范围的查询受益,并且该列的选择性最强,因此已经在很大程度上限制了候选行。

另一方面,(Least, SecondMost, MostSelective)上的索引似乎是一个错误,但实际上它是一个功能强大的索引。因为它的最外面的查询是Least列,所以它可用于必须在低选择性列上聚合结果的查询。这样的查询在OLAP和分析数据仓库中很普遍,而这正是此类索引非常适合的地方。这样的索引实际上是出色的clustered

索引,正是因为它们将物理布局组织在大块相关行上(相同的Least值,通常表示某种类别或类型),并且有助于分析查询。

因此,很遗憾,没有“正确”的命令。您不应该遵循任何曲奇工具的配方,而应针对这些表分析将要使用的查询模式,并确定哪个索引列顺序正确。


43
投票

正如Remus所说,这取决于您的工作量。


30
投票

您应该在索引声明的开头放置最具有选择性的列。


5
投票

所有其他答案都是错误的。

[复合索引中各个列的选择性没有

© www.soinside.com 2019 - 2024. All rights reserved.