SQL Server性能:具有外键约束的复合键

时间:2014-08-24 08:23:58

标签: sql-server query-optimization

考虑一个系统,其中每个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]

我的问题是:

  1. 因为查询优化器可以查找聚簇索引与非聚簇索引,所以会在性能方面获得2或3的好处吗?
  2. 假设选择了方法2,如果构建了CategoryId上的非聚集索引,那么查询优化器将会受益,从而为其提供了更多选项"?
  3. 是否只有基于复合键开头的查询才能从这样的"复合键聚簇索引中获益"?即如果PK是[Id,CategoryId],那么这样的索引在查询... WHERE CategoryId = 123中是无用的吗?
  4. 在复合主键中使用外键是否具有任何性能影响(无论好坏)?
  5. 注意:

    1. 我使用的是SQL Server,但我希望答案对数据库系统来说是通用的。
    2. 我知道类似的问题("复合PK中的FK"以及" FK&#34的表现;)但是没有一个能解决这两个问题的组合。

2 个答案:

答案 0 :(得分:1)

聚集索引是表数据的主要排序机制。表中的所有数据都将按聚簇索引排序。表可以是聚簇索引(已排序)或堆(未排序)。如果没有聚簇索引,该表将被视为堆。

其次,索引根据索引中的列排序从左到右排序。在方法2中,首先搜索CategoryId,然后搜索Id。如果在where子句中只提供了Id,则仍然可以使用索引,但最多只能进行完整的索引扫描。

如果始终使用categoryid和id的组合访问您的消息,则方法2将很有效。但是,如果仅使用id(包括更新和删除)访问消息,并且id是索引中的第二个字段,则可能不会使用索引。这是因为索引被认为是"树",其中最左侧的值位于树的根,右侧列是"分支"。你必须从根开始并逐步解决。

就集群与非集群而言,两者的表现相似。唯一的区别是聚集索引实际上对表中的所有数据进行排序。

摘要:

  1. 可能,是的。
  2. 是的,虽然不是完全无用的。索引扫描仍然可以比表扫描(也称为聚簇索引扫描)更好。
  3. 没有

答案 1 :(得分:1)

优化器的性能不是您唯一的考虑因素。一般来说,您希望群集密钥较小,单调增加且唯一。你的CategoryId建议满足小,但可能是随机的(因此不是单调的),绝对不是唯一的。单调性对于避免物理碎片非常重要。唯一性解释起来有点棘手,但它归结为引擎需要能够唯一地识别行。如果您的密钥不是唯一的,则引擎会向该行添加一个uniquifier,从而使该行更大。