考虑一个系统,其中每个message
只属于一个类别,以及一个仅在选定类别中显示消息的页面。
message
表将构造为:
Id (PK),
CategoryId (FK of [category]),
...
要显示消息,可以使用SELECT * FROM message WHERE CategoryId = 123
。假设此查询非常频繁地执行,那么在CategoryId
字段上构造非聚集索引是明智的。因此,我们有,
方法1(使用伪SQL语法):
Id,
CategoryId,
PK is [Id],
[CategoryId] is FK of [category]
Clustered index on [Id],
Non-clustered index on [CategoryId]
然而,使用Id
操纵消息的可能性非常小。我们可以根据物理光盘中的CategoryId
对邮件进行排序,保存非聚集索引:
方法2:
Id,
CategoryId,
PK is [CategoryId, Id]
[CategoryId] is FK of [category]
Clustered index on [CategoryId, Id]
如何修改方法1,以便不在Id
:
方法3:
Id,
CategoryId,
PK is [Id],
[CategoryId] is FK of [category],
Clustered index on [CategoryId]
我的问题是:
CategoryId
上的非聚集索引,那么查询优化器将会受益,从而为其提供了更多选项"?... WHERE CategoryId = 123
中是无用的吗?注意:
答案 0 :(得分:1)
聚集索引是表数据的主要排序机制。表中的所有数据都将按聚簇索引排序。表可以是聚簇索引(已排序)或堆(未排序)。如果没有聚簇索引,该表将被视为堆。
其次,索引根据索引中的列排序从左到右排序。在方法2中,首先搜索CategoryId,然后搜索Id。如果在where子句中只提供了Id,则仍然可以使用索引,但最多只能进行完整的索引扫描。
如果始终使用categoryid和id的组合访问您的消息,则方法2将很有效。但是,如果仅使用id(包括更新和删除)访问消息,并且id是索引中的第二个字段,则可能不会使用索引。这是因为索引被认为是"树",其中最左侧的值位于树的根,右侧列是"分支"。你必须从根开始并逐步解决。
就集群与非集群而言,两者的表现相似。唯一的区别是聚集索引实际上对表中的所有数据进行排序。
摘要:
答案 1 :(得分:1)
优化器的性能不是您唯一的考虑因素。一般来说,您希望群集密钥较小,单调增加且唯一。你的CategoryId建议满足小,但可能是随机的(因此不是单调的),绝对不是唯一的。单调性对于避免物理碎片非常重要。唯一性解释起来有点棘手,但它归结为引擎需要能够唯一地识别行。如果您的密钥不是唯一的,则引擎会向该行添加一个uniquifier,从而使该行更大。