使用 IN vs = 运算符时在非主键列上使用聚集索引

Posted

技术标签:

【中文标题】使用 IN vs = 运算符时在非主键列上使用聚集索引【英文标题】:Using clustered indexes on non-primary key columns when using IN vs = operator 【发布时间】:2012-02-07 05:15:41 【问题描述】:

如果我的 Product 表有 CategoryId 列,我知道将 CategoryId 设为聚集索引而不是主键 ProductId 可能是一个好习惯。

如果我对 Product 表的大多数查询看起来像 select * from Product where CategoryId in (1, 2) 而不是更典型的 select * from Product where CategoryId = 1,这是否仍然适用

【问题讨论】:

【参考方案1】:

非常小心选择您的聚集索引!它非常特别 - 每个表只能有一个,它决定了数据的物理顺序,它用于唯一标识数据页的位置(“行指针”,如果你愿意的话)。

此外,它是您的 SQL Server 数据库中重复次数最多的数据结构(假设您正在谈论的是 SQL Server)。聚簇键也将成为表中每个非聚簇索引的一部分 - 当然在叶级,也可能在索引导航结构中。

在选择集群键时应该格外小心 - 它应该是:

(4字节理想)

唯一(毕竟它是“行指针” - 如果您不使其唯一,SQL Server 将 - 为您 - 在后台 - 花费您几个字节对于每个条目 - 乘以您拥有的行数和非聚集索引的数量 - 可能非常昂贵!)

静态(永远不要改变 - 如果可能的话)

理想情况下不断增加,这样您就不会出现可怕的索引碎片(GUID 与良好的集群键完全相反 - 出于这个特殊原因)

它应该是不可为空的,并且理想情况下也可以使用 - varchar(250) 使聚类键非常差

除了这些点之外,其他任何事情都应该是第二和第三级的重要性......

查看 Kimberly Tripp(索引女王)关于该主题的一些博客文章 - 她在博客中所写的任何内容都绝对是无价之宝 - 阅读、消化 - 以此为生! p>

GUIDs as PRIMARY KEYs and/or the clustering key The Clustered Index Debate Continues... Ever-increasing clustering key - the Clustered Index Debate..........again!

在您的具体情况下,在Products 表上选择CategoryId 听起来不是一个好主意。一个产品的类别可能会改变,它很可能不是唯一的,因此我认为它不会真正成为一个很好的聚类键。

此外,产品的类别听起来也不是很有选择性 - 所以它甚至可能不会成为一个好的非聚集索引。如果特定查询返回的行数超过总行数的 1-5%,则 SQL 查询优化器无论如何都不会使用大多数索引(因为它们返回的数据太多)。

【讨论】:

这是我第一次阅读这个问题,但我发誓我在某处读过这个完全相同的答案。你只是复制和粘贴你的答案吗?哈哈。 很好的答案和文章,谢谢。对唯一键进行聚类非常不直观 - 我将不得不再阅读几次。 “Products 表上的CategoryId 听起来不是一个好主意......它很可能不是唯一的”——我认为它们的意思是(CategoryId, ProductId) 复合上的聚集索引按这个顺序,这个想法是,当仅通过CategoryId 搜索时,结果将大部分位于相同的物理页面上。 @onedaywhen:(CategoryId, ProductId) 上的那个化合物会是更好的选择,是的!

以上是关于使用 IN vs = 运算符时在非主键列上使用聚集索引的主要内容,如果未能解决你的问题,请参考以下文章

我应该摆脱 Guid 列上的聚集索引吗

表格存储 SQL 查询多元索引

如何使用 JPA 和 Hibernate 在非主键上连接表

MySql的InnoDB存储引擎--索引

如何在Django中加入非主键和外键列的查询

具有序列提供的 id 的主键列上的唯一约束违规