2

假设我有下表:

Table: RelationshipType
============================================================
|  ID (PK)  |  ParentID  |  ChildID  |  RelationshipType   |
============================================================

大多数情况下,ParentIDChildID是单独选择的:

... WHERE ParentID = @SomeID

... WHERE ChildID  = @SomeID

有时两者都被选中:

... WHERE ParentID = @SomeID AND ChildID  = @SomeOtherID

我想提高这些查询的性能,但最值得注意的是前两个。ParentID我应该在+上创建一个非聚集索引,ChildID还是在一个索引上创建ParentID另一个索引ChildID

编辑: 所有这些查询都是高度选择性的(返回 1 或 2 条记录)。

4

4 回答 4

3

你能摆脱代理键ID吗?

如果是,请考虑创建以下内容:

  • 上的主键和集群{ParentID, ChildID}
  • 上的二级索引{ChildID, ParentID},但也包含RelationshipType在索引中(使用INCLUDE关键字)。

这样,您在所有 3 种情况下都有一个覆盖索引,因此您不必支付双重查找的代价(这通常是聚簇表中的二级索引所必需的):

  • ... WHERE ParentID = @SomeID可以通过在索引的 B-Tree 中进行简单的查找来满足:{ParentID, ChildID}. ChildIDRelationshipType1的值可以直接从这个 B-Tree 的找到的叶子中检索。
  • ... WHERE ChildID = @SomeID可以通过在索引的 B-Tree 中进行简单的查找来满足:{ChildID, ParentID}. ParentIDRelationshipType2的值可以直接从该 B-Tree 的找到的叶子中检索。
  • ... WHERE ParentID = @SomeID AND ChildID = @SomeOtherID两者都可以满足。

1聚类键是表的“主”B 树,包括所有列,而不仅仅是唯一的列。

2感谢INCLUDE (RelationshipType)


与现在做类似的事情ID是可能的,但需要 3 个索引而不是 2 个,并且所有这些索引都会更胖以实现覆盖。你必须测量以确保,但我的感觉是,这将比它的价值更麻烦。

否则,根本不要使用集群。只需在以下位置创建普通索引:

  • {ID}- 常规的非聚集主索引(使用 NONCLUSTERED 关键字)。
  • {ParentID}- 常规二级索引。
  • {ChildID}- 常规二级索引。

您将拥有一个普通的堆表,因此每次访问都需要索引搜索 +(通常)表堆访问,但您的索引将保持苗条,从而提高缓存效率。

... WHERE ParentID = @SomeID AND ChildID = @SomeOtherID将需要两次索引查找(或者可能在其中一个{ParentID}{ChildID}索引+表堆访问上进行查找),但这仍然非常快并且不太频繁(如您所述)。


在决定任何一种方式之前,请务必测量实际数据量。

于 2013-01-21T17:53:44.287 回答
1

正如您所说的那样查找ParentId或者ChildId是高度选择性的,我只会选择两个单独的索引。

然后,SQL Server 可以使用任一索引来WHERE ParentID = @SomeID AND ChildID = @SomeOtherID计算匹配的一或两行的剩余谓词。

我想一个例外是,如果表或多或少是只读的并且整个数据库适合内存,那么拥有附加索引没有不利的一面,它避免了查找以检索丢失的列。

于 2013-01-21T12:22:48.287 回答
1

在某种程度上,如果不知道每个选择的频率以及对表的插入/更新发生的频率,就不可能说什么会给您的数据库带来最佳性能,但这是我最好的猜测:

听起来像 ParentID,ChildID 可能是你的主键,根据定义它是一个聚集索引。

这里的懒惰方法是在 ParentID 和 ChildID 上再创建两个非聚集索引。但是...尤其是 ParentID 列,或任何列在您的主键/集群索引中的第一个列 - 如果您创建另一个非集群 ParentID 索引,我真的不确定您是否会获得任何选择收益。非聚集索引将存储按该索引排序的表的副本,但在这种情况下,主键决定了表的顺序,并且它已经首先按 ParentID 排序。

所以总而言之,我会在 ChildID 上创建一个 ParentID 和 ChildID 的主键和一个非聚集索引,我认为你很高兴。

于 2013-01-21T12:24:42.190 回答
1

我会在每一列上创建一个非聚集索引,但包括另一列以及RelationshipType 列(我假设RelationshipType 是您正在检索的数据):

CREATE NONCLUSTERED INDEX IX_RelationshipType_ParentID
ON
    RelationshipType(ParentID)
INCLUDE
    (ChildID, RelationshipType)
GO

CREATE NONCLUSTERED INDEX IX_RelationshipType_ChildID
ON
    RelationshipType(ChildID)
INCLUDE
    (ChildID, RelationshipType)
GO

这将导致引擎一旦找到条目就能够从索引中获取所需的数据,而无需在找到索引中的项目后返回表。

于 2013-01-21T12:36:45.370 回答