SQL Server 聚集索引 - 索引顺序问题

Posted

技术标签:

【中文标题】SQL Server 聚集索引 - 索引顺序问题【英文标题】:SQL Server Clustered Index - Order of Index Question 【发布时间】:2010-09-25 12:52:35 【问题描述】:

我有一张这样的桌子:

keyA keyB data

keyA 和 keyB 是唯一的,是我的表的主键,组成了一个聚集索引。

keyB 有 5 个可能的值,但 keyA 的可能值的数量是无限的。 keyB 通常递增。

例如,根据先排序哪个键列,可以对以下数据进行 2 种排序:

keyA keyB data
A    1    X
B    1    X
A    3    X
B    3    X
A    5    X
B    5    X
A    7    X
B    7    X

keyA keyB data
A    1    X
A    3    X
A    5    X
A    7    X
B    1    X
B    3    X
B    5    X
B    7    X

我是否需要告诉聚集索引哪些键列具有较少的可能值,以允许它首先按该值对数据进行排序?还是说性能优先不重要?

【问题讨论】:

【参考方案1】:

您应该首先使用最具选择性的列来排序复合聚集索引。这意味着与总行数相比,具有最不同值的列。

“B*TREE 索引提高了从表中选择一小部分行的查询的性能。” http://www.akadia.com/services/ora_index_selectivity.html?

本文适用于 Oracle,但仍然适用。

另外,如果您有一个持续运行并返回少量字段的查询,您可以考虑创建一个包含所有字段的复合索引 - 它不必访问基表,而是从索引中提取数据。

ligget78 关于确保提及复合索引中第一列的评论很重要。

【讨论】:

您能否再澄清一下“最具选择性的专栏”?出于某种原因,“这意味着与总行数相比,具有最不同值的列。”似乎有点混乱。你是说这个例子中的答案是把 KeyA 放在聚集索引的前面吗? (第二个例子?) -1:您没有回答实际问题。您提到了一些与一般性能相关的事情,但它们在这里无关紧要。您为第一段提供零参数 could 是一个有效的答案,但目前未经证实。您链接到的文章似乎也不是很相关。【参考方案2】:

如果您使用 (keyA, keyB) 创建索引(无论是否聚集),那么这就是值的排序方式,例如首先是keyA,然后是keyB(这是您问题中的第二种情况)。如果你想反过来,你需要指定 (keyB, keyA)。

这在性能方面可能很重要,当然取决于您的查询。例如,如果您有 (keyA, keyB) 索引,并且查询看起来像 WHERE keyB = ...(没有提及 keyA),则无法使用该索引。

【讨论】:

【参考方案3】:

正如其他人所说,排序基于您在索引创建脚本(或 PK 约束)中指定的方式。不过,关于聚集索引的一件事是需要牢记很多。

通过在 PK 以外的其他对象上使用聚集索引,您可能会获得更好的整体性能。例如,如果您正在编写财务系统并且报告几乎总是基于活动的日期和时间(过去一年的所有活动等),那么该日期列上的聚集索引可能会更好。正如 HLGEM 所说,您选择的聚集索引也会影响排序。

与其他索引相比,聚集索引对插入的影响也更大。如果您有大量插入,并且您的聚集索引位于 IDENTITY 列之类的位置,那么磁盘的特定部分可能会出现争用问题,因为所有新行都被插入到同一个位置。

对于小型查找表,我总是将聚集索引放在 PK 上。对于影响较大的表,最好在选择最佳索引之前花时间考虑(和测试)各种可能的聚集索引。

【讨论】:

【参考方案4】:

我相信 SQL Server 完全按照您所说的方式对其进行排序。它假定您最了解如何访问您的索引。

在任何情况下,我都会说最好在可能的情况下准确地指定您想要的内容,而不是希望数据库能够弄清楚。

您也可以尝试这两种方式,运行一组有代表性的查询,然后比较生成的执行计划以确定哪种方式最适合您。

【讨论】:

投了赞成票,但只是想指出,虽然在这种情况下指定你想要的东西很好,但通常你应该让服务器找出最好的东西。例如,在查询中使用索引提示通常不是一个好主意,因为最佳计划可能会随着数据的变化而变化。 同意。索引提示是万不得已的邪恶蛮力解决方案。我指的是以两种方式创建索引本身,然后测试有代表性的查询。 (反正我就是这么做的:))【参考方案5】:

请记住,聚集索引是表存储在磁盘上的物理顺序。

因此,如果您的聚集索引被定义为 ColA,则 ColB 查询在以与聚集索引相同的顺序排序时会更快。如果 SQL 必须对 B、A 进行排序,则需要执行后排序才能达到正确的顺序。

我的建议是在 B、A 上添加第二个非聚集索引。还取决于您的数据列的大小来包含(读取包含的列)它以防止需要键查找。当然,前提是该表没有大量插入,因为您始终必须平衡查询速度与写入速度。

实际上,您的聚集索引应该代表最有可能访问数据的顺序,并保持插入\更新 IO 成本的微妙平衡。如果您的聚集索引经常插入到页面中间,您可能会在那里遭受性能损失。

正如其他人所说,不知道表格长度、列大小等,就没有正确答案。进行大量测试的反复试验是最好的选择。

【讨论】:

【参考方案6】:

以防万一这不是很明显:索引的排序顺序并不能保证查询中结果的排序顺序。 p>

在您的查询中,您仍然必须添加一个

ORDER BY KeyA, KeyB

ORDER BY KeyB, KeyA

优化器可能很高兴找到已在索引中按物理顺序排列的数据并节省一些时间,但每个按特定顺序传递数据的查询都必须在其末尾有一个 ORDER BY 子句。如果没有 order by,SQL Server 不会对记录集的顺序做出任何承诺,甚至不会承诺它会以相同的顺序从一个查询到另一个查询返回。

【讨论】:

【参考方案7】:

您可以做的最好的事情是尝试两种解决方案并测量执行时间。

根据我的经验,索引调优几乎是一门精确的科学。

也许在索引列顺序中在 keyA 之前有 keyB 会更好

【讨论】:

它实际上是基于具体的科学思想。稍微了解一下 b-tree 索引的工作原理将使您更了解情况,并且需要更少的猜测工作。 +1 表示诚实。除非您确切知道(例如)SQL Server 在内部是如何工作的,否则您无法确定实际情况如何。不过理论很棒。不,真的;)【参考方案8】:

您可以按照通常希望它们在报告和查询中排序的顺序来指定列。

不过,我会警惕创建多列聚集索引。根据它的宽度,您可能会对您创建的任何其他索引的大小产生巨大影响,因为所有非聚集索引都包含其中的聚集索引值。此外,如果值经常更改,则必须重新排序行,根据我的经验,非代理键往往会更频繁地更改。因此,如果您的值可能会更改,那么将其创建为聚集副非聚集索引可能会耗费更多的服务器资源时间。我并不是说您不应该这样做,因为我不知道您的列实际包含什么类型的数据(尽管我怀疑它们比 A1、a2 等更复杂);我是说你需要考虑这样做的后果。在承诺这样做之前,彻底阅读 BOL 关于聚集副非聚集索引可能是一个好主意。

【讨论】:

【参考方案9】:

是的,您应该建议,通常查询引擎会尝试找出最佳执行计划和要使用的索引,但有时最好强制查询引擎使用特定索引。在规划索引以及在查询中使用索引时,还有其他一些注意事项。例如,索引中的列排序,where 子句中的列排序。您可以参考以下链接了解:

http://ashishkhandelwal.arkutil.com/sql-server/quick-and-short-database-indexes/

使用索引的最佳实践 如何获得最佳性能表单索引 聚集索引注意事项 非聚集索引注意事项

我相信这会对您规划索引时有所帮助。

【讨论】:

以上是关于SQL Server 聚集索引 - 索引顺序问题的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 中多列非聚集索引中的列顺序是不是重要?

sqlserver的索引

聚集和非聚集索引 - SQL Server 和 Oracle?

翻译-聚集索引《Pro SQL Server Internals, 2nd edition》

SQL Server:聚集和非聚集索引[重复]

sql-server学习:索引