具有唯一列的非聚集索引是否总是首先解决过滤该列的所有查询?

Mag*_*ier 4 index sql-server sql-server-2008-r2 index-tuning nonclustered-index

我发现过索引的大型堆表,例如有多个不同的非聚集索引和不同的列,但其中一些索引将(只有一个)主键列设置为它们的第一个索引列。

我进行了一些调查,使用了索引和查询,并得出了我希望专业人士确认的结论。

问题1:我说基于主键的多个索引而不是仅基于主键列的一个索引作为第一个也是唯一的索引列是无稽之谈,因为所有使用此pk进行过滤或加入的查询都返回只有一行?(假设额外的过滤、连接或选择的列作为包含列放入索引中以完全覆盖查询并避免 RID 查找)

问题 2:基于表主键的非聚集索引应该始终创建为 UNIQUE 索引,这样说对吗?(无论出于何种原因,该设置都是可选的,因为 sql server 应该已经知道包含 pk 的索引将是唯一的...)

Pau*_*ite 6

  1. 是的,考虑到问题中的约束,特别是主键列是索引中的前导列。还假设主键永远不会改变。

  2. 不必要。

    优化器确实可以在不将非聚集索引标记为唯一的情况下推断出唯一性。

    将索引标记为唯一可能会在更改索引键的执行计划中引入拆分-排序-折叠组合。特别是额外的 Sort 有可能影响性能。

    另一方面,如果主键发生更改,则不将索引标记为唯一会带来数据完整性的风险。

例子

CREATE TABLE dbo.Test
(
    pk integer PRIMARY KEY NONCLUSTERED,
    c1 integer NOT NULL,
    c2 integer NOT NULL
);

-- Not unique on pk, c1
CREATE NONCLUSTERED INDEX ic1 ON dbo.Test (pk, c1);

-- Unique on pk, c2
CREATE UNIQUE NONCLUSTERED INDEX ic2 ON dbo.Test (pk, c2);
Run Code Online (Sandbox Code Playgroud)

唯一性

-- Neither plan has an aggregate
SELECT DISTINCT T.c1 FROM dbo.Test AS T WHERE T.pk = 1;
SELECT DISTINCT T.c2 FROM dbo.Test AS T WHERE T.pk = 1;
Run Code Online (Sandbox Code Playgroud)

没有聚合

拆分、排序、折叠

-- No split, sort, collapse
UPDATE dbo.Test SET c1 = CHECKSUM(NEWID());
Run Code Online (Sandbox Code Playgroud)

简单更新

-- Split, sort, collapse updating unique key
UPDATE dbo.Test SET c2 = CHECKSUM(NEWID());
Run Code Online (Sandbox Code Playgroud)

共享服务计划

请注意 split-sort-collapse 计划也是一个广泛的(每个索引)更新

不过,独特性是一个巨大的话题。我通常会将独特的东西标记为独特,除非有充分的理由不这样做。从我的博客进一步阅读:


预测有关堆表的评论:大多数表都受益于集群。您需要有充分的理由来选择堆结构,尤其是从空间管理的角​​度来看,如果表曾经经历过删除。如果列扩展到超出原始页面上的可用空间(转发的记录),更新也会对性能产生影响。