为什么索引视图不允许非唯一聚集索引?


12

我一直在研究使用索引视图来提高一些我们最常用的视图的性能。

但是,索引视图不支持非唯一的聚集索引,这与其余数据库结构设置的优先级略有不同。

例如,这是几个表的简化版本。

-Groups-
Group ID    GroupName

-Users-
UserKey    UserName    FullName     GroupID

索引位于Groups.GroupID(非群集)和Users.GroupID(群集)上。聚簇键位于“用户”表中的GroupID上,因为通常会检索到来自特定组的一系列用户。显然,每个组将有多个用户,因此该聚集索引是唯一的。

这使我不确定如何在索引我的视图(例如本示例)时遵循此优先顺序,因为我无法拥有非唯一的聚集索引。

ConsumableID    ConsumableVariantID AllowThresholdOverwrite FullPath    GroupID ManufacturerID  Type    ModelID
101              29                 1                       0.1.2.4.    4       3               3       2

实际上,此View上唯一唯一的值是ConsumableID列,因此在将索引放置到什么地方时,我别无选择。

为什么在常规表允许时View不允许非唯一聚集索引?


3
页面底部附近有一个非常简短的解释,标题为“为什么必须对视图的第一个索引进行聚类和唯一化?” 但这并没有太多细节。我绝对希望听到更详细的解释。
Steve Pettifer 2014年

5
几点评论:1-没有理由不能聚集在上(GroupID, UserID)。不要将自己限制在密钥的单个列中。2-我认为视图的局限性是因为这是一个补充数据对象,需要使行轻松绑定到NC索引。对于一个表,非唯一CI键将附加一个int值,但我认为对于索引视图而言,这将更具挑战性,因为它不是实际表,而是需要反射实际表。
JNK 2014年

Answers:


22

此Microsoft技术文章中给出了以下解释:

为什么视图中的第一个索引必须是CLUSTERED和UNIQUE?

它必须是唯一的,以允许在索引视图维护期间通过键值轻松查看视图中的记录,并防止创建具有重复的视图,这将需要特殊的逻辑来维护。它必须是群集的,因为只有群集的索引才能强制执行唯一性并同时存储行。

SQL Server使用增量代数系统来使索引视图与基础数据保持一致。它还会为影响一个或多个索引视图的每个DML查询自动合并视图维护查询计划运算符。在视图上具有唯一的聚簇索引可以极大地简化实现细节。

当前的安排允许将固定形状的维护运算符树形状合并到基本DML查询树中,从而提供正交性,从而也简化了测试。最终,索引视图可以在一天之内得到增强,以支持非唯一的聚集索引,但是在无限制的时间和无穷的资源(编写本文时,这两种方法都不适用于SQL Server开发团队)下,所有事情都可以再次实现。

有关显示如何构建复杂的更新查询计划以及如何轻松潜入细微错误的示例,请参见此示例,该示例在MERGE索引已过滤的情况下发生(该功能与索引视图密切相关)。


2
如果您尝试更新具有GROUP BY子句但并非所有分组表达式都是聚集索引中的键的索引视图,则可能会发生类似的错误。自SQL Server 2014起有效
。– Quassnoi

4

在SQL Server中,所有索引键在内部必须唯一。要获得恰好寻址一行的锁定键,这是必需的。索引维护也需要它。想象一下,一列中只有一个值(100%重复)的NCI。如果从表中删除了一行,则存储引擎必须找到相应的NCI行并将其删除。如果所有NCI行都无法区分,则这将是不可能的。

因此,您将看到视图上的配置项必须(内部)唯一,引擎才能正常工作。

如果您不使索引唯一,SQL Server仍将使其在内部唯一。对于堆表上的NCI,它会附加行书签。如果是非唯一CI,则会添加一个uniquifier列。如果在带有配置项的表上使用NCI,则会将您自己尚未指定的所有配置项键列追加(可能包含唯一符)。

对于索引视图,没有明显的列可以追加。因此,SQL Server无法自动执行此操作。

通常,对于人类来说,很明显可以添加哪些列以使视图具有在CI中使用的唯一列集。这些通常是基础表之一的PK或CI列。如果视图GROUP BY通常在分组键上索引。


2
我强烈建议修改此答案的措词。尽管它包含有关原始问题的有效观点,但看起来它似乎暗示所有非唯一索引都包含唯一符,而事实并非如此。
spaghettidba

@spaghettidba谢谢,我没有注意到。希望现在更好。
usr 2014年

抱歉,还没有。您正在将两件事混合在一起。非聚集索引不必是唯一的,在内部也不是唯一的:您没有足够清楚地说明这一点。您在答案中说的所有内容仅适用于聚集索引。
spaghettidba

@spaghettidba NCI在内部始终是唯一的。他们始终可以将所有CI键作为查询计划的一部分输出。请参见pastebin.com/vkGHpCsR。NCI数据页面包含两列。
usr

我知道你来自哪里。多个叶子可以共享相同的索引关键字,但是群集关键字始终包含在NCI中。足以说它们在内部始终是唯一的吗?我不这么认为。
spaghettidba
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.