假设我有一张这样的表:
CREATE TABLE t(
[guid] [uniqueidentifier] NOT NULL,
[category] [nvarchar](400)
{,...other columns}
)
guid
是我的主键,并且有一个聚集索引。
现在,我想要一个涵盖 category
和guid
的索引,因为我按类别汇总了与t
相关的其他内容,我想避免包含t
表本身。
创建覆盖category
的索引是否已足够,或者我是否还需要包含guid
?
我希望SQL Server索引直接指向t
中的页面偏移,而不是简单地引用guid
主键值,这意味着我 需要明确包括PK列以避免命中t
。是这种情况吗?
答案 0 :(得分:2)
实际上您的假设是错误 - 所有SQL Server非群集索引都包含群集密钥(单列或多列)并且不直接指向某个物理页面。
这可以防止SQL Server在页面需要拆分为两个或重新定位时重新组织和更新大量索引条目。因此,如果您在非聚集索引中寻找并找到值,那么您将拥有聚类键,SQL Server将需要执行“书签查找”(或键查找)以检索实际数据页(叶页)在聚类索引中)获取属于单行的整个数据集。
那就是说 - 如果你有一种情况,它依赖于键列的排序,那么你仍然可能需要专门在(guid, category)
上创建一个索引 - 当然,在这种情况下,SQL Server是聪明到足以弄清楚聚类键列已经在索引中,并且不再添加它了。
群集密钥列包含在每个非聚集索引中的事实是您的群集密钥应该是窄的,静态的和唯一的另一个强有力的原因。使它们太宽(超过8字节的任何东西)是膨胀和减速的可靠方法。
答案 1 :(得分:1)
与marc_s的答案略有不同。
(category,guid)上的覆盖索引将对主键排序的GUID具有不同的排序。因此,guid可能在索引中出现两次,因为它位于键列列表和指向聚簇索引的指针中。
如果您INCLUDEd(作为非键列)guid SQL Server将不再添加它。
我现在无法测试密钥列,但我在SQL Server 2005之前已经验证了INCLUDE。