5

好的,我需要再说明一次。我在网上看过文章,但我仍然没有找到明确的答案。

在 SQL Server 2008 中,我有一个“核心”表,其中包含大约 50k 条记录和大量读取活动,在所有查询中都以相同的方式使用。该数据每月更新一次,每秒读取数百次。

数据在字段上具有聚集索引,因为它们经常被访问。假设聚集索引是:

聚集索引

Field1 int
Field2 int
Field3 int
Field4 int
Field5 int

现在,没有比这更多的数据了,因此将额外的几列放入“包含的列”是有意义的,但 SQL Server 不允许在聚集索引中包含列。

因此,我们有第二个索引,其字段与聚集索引基本相同,其他列为“包含列”。但是,根据我的阅读,我相信这可能是多余的?

覆盖索引(非聚集)

Field1 int
Field2 int
Field3 int
Field4 int
Field5 int

包含的列

Field6 varchar(96)
Field7 varchar(96)

非聚集索引是否已经定义了聚集索引中的列?

如果是这样,那么如何创建第二个索引时根本没有列(除了聚集索引中已经存在的内容)?换句话说,我想说“这个索引与聚集索引完全相同......带有几个包含列”。

或者,将所有列放入聚集索引(包括不识别记录的两个)会更好吗?varchar 列确实会更频繁地更新(每天几次而不是每月一次),所以我希望将它们排除在聚集索引之外,但我认为它们足够深,不会影响索引树足以在发生更改时引起任何重新平衡。

那么,有没有一种有效的方法来设置这些索引,以便该表的所有列都可以通过索引获得,而无需返回该表?

4

4 回答 4

5

是 - 非聚集索引通过聚集键访问表中的数据(当表有聚集键时,如果没有聚集键,则使用行 ID),因此它将自动包含聚集索引字段。这也是为什么更改聚集索引会强制重建所有非聚集索引的原因。

如果该索引满足大量查询,那么包含 2 个字段的附加 NC 索引可能是有效的,但我不确定这是否解决了正确的问题。

在 Clustered Key 中再包含 2 个字段并不理想,现在它在 NC 索引中得到确认,您可以看到该表上的每个索引都包含其中的 clustered key,将每个索引都放大了。

这是您希望集群键尽可能窄的主要原因,如果有的话,您应该检查集群键,询问您为什么选择 5 字段集群键,该选择会导致碎片吗?

您最好为聚集键使用人工值(身份),并使用唯一的 NC 索引来强制使用 5 字段聚集键的唯一性。

于 2011-01-02T17:01:41.320 回答
4

聚集索引不需要包含。包括意味着在索引树的最低级别存储了额外的数据。这聚集索引中的数据。所以你不需要重叠索引

但是,如果您关心内存占用,那么您需要缩小表。对于 50k 行,我会考虑从 -32768 开始的 smallint 代理键。然后,您删除每个 NC 索引中 C 键的开销。这意味着您可以拥有问题中提到的覆盖索引。

请注意,一旦您的执行计划被缓存并且数据在缓存中,那么您的查询将来自内存。您的使用意味着它将在缓存中保留一段时间。缺乏更新意味着你不会得到统计驱动的重新编译。

但是,如果您的数据几乎是静态的,那么如果考虑性能,为什么还要调用 SQL Server?缓存它。根据我的缓存评论,删除可能是您最大的开销的网络往返。我们将一些查找和缓存外包给我们的客户以减少服务器负载(在峰值负载时,我们在大约 20 秒内有 50k 次写入)

于 2011-01-02T18:37:00.923 回答
1

将额外的几列放入“包含的列”中是有意义的,但 SQL Server 不允许在聚集索引上包含列

包含额外的列是不可能的,因为聚集索引已经包含所有列。这就是索引被称为聚集索引的原因。

因此,我们有第二个索引,其字段与聚集索引基本相同,其他列为“包含列”。但是,根据我的阅读,我相信这可能是多余的?

是的,这可能是多余的。有一些罕见的例外情况是聚集索引不适合内存。

非聚集索引是否已经定义了聚集索引中的列?

可能:非聚集索引包含指向聚集索引的指针。如果聚集索引是唯一的,则此指针由所有聚集索引字段组成。(在大多数情况下,这些字段与主键相对应。)

那么,有没有一种有效的方法来设置这些索引,以便该表的所有列都可以通过索引获得,而无需返回该表?

在您发布的示例中,聚集索引似乎就足够了,并且您不需要任何其他索引来避免表查找。您可以通过运行查询并查找“键查找”或“消除查找”操作来验证这一点。

于 2011-01-02T17:02:07.270 回答
1

我认为您需要更好地了解 CLUSTERED 和 NONCLUSTERED 索引。聚集索引是一个平衡树(B 树),其中每个节点都包含索引的键列。通常,并且经常是最好的选择,一列是索引的键列。每行的所有数据都存储在聚集索引的叶级(即底层)。这就是为什么不能在聚集索引中包含列的原因;根据定义,所有列都包含在内。

非聚集索引也是 B 树结构。每个节点都包含索引的键列。非聚集索引的叶级别包含任何包含的列。请注意,键列和包含列之间的区别在于,键列值出现在索引的每个级别,而包含列仅出现在叶级别。叶级还包含来自聚集索引的键列,用于将索引链接到表数据。

您在任何索引中包含的列越多,索引就越大。而且,这会降低性能。

因此,对于聚集索引,您不需要将所有列,甚至许多列都包含在索引中作为键。数据已经是索引的一部分。

于 2011-01-02T17:02:51.127 回答