两列上的单个非聚集索引或每列上的单独索引?

时间:2013-01-21 12:14:26

标签: sql sql-server sql-server-2008 tsql database-design

假设我有下表:

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 个答案:

答案 0 :(得分:3)

你可以摆脱代理键ID吗?

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

  • {ParentID, ChildID}上的主要和clustering密钥。
  • {ChildID, ParentID}上的辅助索引,但也包含索引中的RelationshipType(使用INCLUDE关键字)。

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

  • ... WHERE ParentID = @SomeID可以通过索引的B树中的简单搜索来满足:{ParentID, ChildID}ChildIDRelationshipType 1 的值可以直接从此B-tree的已找到的叶子中检索。
  • ... WHERE ChildID = @SomeID可以通过索引的B树中的简单搜索来满足:{ChildID, ParentID}ParentIDRelationshipType 2 的值可以直接从此B-tree的已找到的叶子中检索。
  • ... WHERE ParentID = @SomeID AND ChildID = @SomeOtherID可以满足。

1 群集密钥是表的“主”B-Tree,包括所有列,而不仅仅是那些唯一的列。

2 感谢INCLUDE (RelationshipType)


可以使用ID执行类似的操作,但是需要3个索引而不是2个,并且所有索引都会更加丰富以实现覆盖。你必须采取措施以确保,但我的感觉是,这将比它的价值更麻烦。

否则,根本不要使用群集。只需在:

上创建普通索引
  • {ID} - 常规非群集主索引(使用NONCLUSTERED关键字)。
  • {ParentID} - 常规二级索引。
  • {ChildID} - 常规二级索引。

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

... WHERE ParentID = @SomeID AND ChildID = @SomeOtherID需要两次索引搜索(或者可能是对{ParentID}{ChildID}索引+表堆访问的搜索),但这仍然非常快且不太频繁(如你所说)。


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

答案 1 :(得分:1)

如你所说,ParentIdChildId的选择具有高度的选择性,我只想选择两个独立的索引。

然后,SQL Server可以使用WHERE ParentID = @SomeID AND ChildID = @SomeOtherID的索引,并评估匹配的一行或两行的残差谓词。

我认为如果表是或多或少是只读的并且整个数据库适合内存那么会有一个例外,那么没有额外索引的缺点并且它避免了查找以检索丢失的列。

答案 2 :(得分:1)

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

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

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

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

答案 3 :(得分: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

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