复合主键/聚簇索引,碎片,性能

时间:2014-01-22 03:25:33

标签: sql sql-server database database-administration

经过20年的专业发展,在数据库性能的某些方面,我仍然感到完全无能为力。这是其中一次。关于表和索引碎片及其对性能的影响,这里和其他地方有成千上万的问题。我知道基本的做法和不做,但有时似乎没有“好”的答案。这是我的问题,我经常遇到它:

表仅用于存储定义一对多关系的id对,让我们使用一个朋友的例子。 Friends表仅包含 personId(int),friendId(int)。每一对当然都是独一无二的。 (因此,但可能与问题无关,每个关系的逆对也存在。)因此,非常小的数据样本将是:

1001, 1011
1001, 1012
1001, 1013
1011, 1001
1012, 1001
1013, 1001
etc...

人1001有3个朋友,当然每个朋友都有1001个人作为朋友等。这个表可能有数百万,甚至多达数亿的关系(行),任何给定的人都会很可能在数百名朋友附近。并且它们将被插入和更新(实际上在这种情况下,一些现有的被删除,新添加,没有实际的行更新)经常,并且没有特定的顺序。对于任何给定批次的插入,它们可以通过 personId,friendId 进行排序,但除此之外,插入在很大程度上会随着时间的推移而无序。

此表的用法是查询给定人员的所有朋友,或内部联接查询人员以分组和汇总与每个人的朋友等相关的其他数据,这是您期望的典型用途。一对多关系表。查询性能可能比插入性能更重要,但两者都很重要,因为两者都会频繁发生。示例查询:

SELECT p.Name FROM Friends f
INNER JOIN People p ON f.friendId = p.id
WHERE f.personId = @personId

在过去,我甚至没有考虑过两次,我会给表一个 personId,friendId 的复合主键,它在SQL Server中默认会创建为聚簇索引,并且可以完成用它。但是我以前从未处理过如此大的和性能关键的数据,所以我质疑这个决定。我没有看到任何方式可以以不会导致显着和频繁碎片的方式构建这样的表。我的问题是:

  1. 有没有更好的方法来构建这些数据?

  2. 考虑到聚集索引的两个int列代表表中的唯一数据,碎片可能与我假设的一样糟糕,如果是这样,这些条件下的碎片是否会导致重要正如我所假设的那样,性能受到了冲击?

  3. (除非RDBMS中有一些根本不同的概念我不熟悉,我假设第一个问题的答案是否定的。所以主要是第二个问题我希望有人有很好的经验基础从BTW来看,数据库是SQL Azure,如果这有所不同的话。)

    非常感谢那些有远见卓识的DBA大师!

2 个答案:

答案 0 :(得分:4)

您只有聚集索引,包括两个字段。索引是有序数据,无论它是否为群集。 如果创建非聚簇索引,则数据将加倍,并且每个插入操作都需要加倍资源,因为它将在堆(或row_id聚簇索引)和非聚簇索引中插入数据。但是搜索操作将仅使用非聚集索引,因为所有需要的数据都包含在其中。

所以制作聚集索引并开心:)

答案 1 :(得分:-1)

您可以在一段时间内重新组织表(CTAS等)以解决碎片问题。

然而,最重要的是,我建议调整SQL和wd高度不鼓励用'朋友'加入'人',因为在这种情况下人们似乎也是大桌子。

为了让您的查询执行得更快,我首先要将您的SQL调整为:

SELECT f.*, p.NAME FROM 
(
SELECT personId, friendId FROM Friends f
WHERE f.personId = @personId
) f
, People p ON f.friendId = p.ID

试一试,看看......