我在SQL,特别是SQL 2005中有一系列关于键,索引和约束的问题。我已经使用SQL大约4年了但是我从来没有能够得到关于这个主题的明确答案,并且在博客帖子等方面总是存在矛盾的信息。我创建和使用的大多数时间表只有一个Identity列,是一个主键,其他表通过外键指向它。
使用连接表我没有Identity并在Foreign Key列上创建复合主键。以下是我目前所信仰的一系列陈述,可能是错误的,如果有,请纠正我,以及其他问题。
所以这里是:
据我了解,Clustered和Non Clustered Index之间的差异(无论是否为Unique)是Clustered Index影响表中数据的物理排序(因此表中只能有一个) ),而非聚集索引构建树数据结构。在创建索引时,我为什么要关心Clustered vs Non Clustered?我什么时候应该使用其中一种?有人告诉我,非聚集索引的插入和删除速度很慢,因为树需要“重建”。我认为Clustered索引不会以这种方式影响性能吗?
我发现主键实际上只是唯一的群集索引(它们是否必须被群集?)。主键与群集唯一索引有什么特别之处?
我也看过Constraints,但我从未使用它们或者真的看过它们。有人告诉我,约束的目的是强制数据完整性,而索引则是针对性能。我还读到,无论如何,约束都是作为索引实际实现的,因此它们是“相同的”。这对我来说听起来不对。约束如何与索引不同?
答案 0 :(得分:2)
Clustered indexes是关于表中数据如何物理存储的定义,即您使用聚类键对B树进行了排序,并且您在叶级别拥有数据。
另一方面,Non-clustered indexes是单独的树结构,它们在叶级别只有集群密钥(如果表是堆,则为RID),这意味着当您使用非聚集索引时,将不得不使用聚集索引来获取其他列(除非您的请求被非聚集索引完全覆盖,如果您只请求构成非聚簇索引键列的列,则会发生这种情况。) p>
什么时候应该使用其中一种?好吧,因为你只能有一个聚簇索引,所以在最有意义的列上定义它,即当你大多数时候按ID查找客户端时,在ID上定义一个聚簇索引。应该在不常使用的列上定义非聚集索引。
关于性能,更改索引键的插入或更新总是很痛苦,无论它是否是非聚集索引,因为页面拆分可能会发生,这会强制数据在页面之间移动(移动页面)聚集索引会受到更多伤害,因为叶级别中有更多数据)。因此,一般规则是避免更改索引键并插入新值以使它们具有顺序性。否则,您将遇到碎片,并且必须定期重建索引。
最后,关于约束,根据定义,它们与索引无关,但SQL服务器已选择使用索引实现它们。例如。目前,一个唯一约束被实现为索引,但是这可能会在未来版本中发生变化(尽管我怀疑会发生这种情况)。索引的类型(聚簇与否)取决于您,只需记住您只能拥有一个聚簇索引。
如果您对此类型有更多疑问,我强烈建议您阅读this book,其中深入介绍了这些主题。
答案 1 :(得分:1)
您对clustered vs non-clustered的假设非常好
主键似乎强制执行非null uniquenes,而唯一索引不强制执行非null primary vs unique
答案 2 :(得分:1)
主键是关系数据库理论中的逻辑概念 - 它是一个关键(通常也是一个索引),旨在唯一标识您的任何行。因此它必须是唯一的,并且不能为NULL。
群集密钥是SQL Server的存储 - 物理概念。它是一个特殊的索引,不仅用于查找等,还定义了表中数据的物理结构。在西欧文化的印刷电话簿中(冰岛除外),聚集索引将是“LastName,FirstName”。
由于聚类索引定义了您的物理数据布局,因此您只能拥有其中一个(或者没有 - 不推荐使用)。
群集密钥的要求是:
默认情况下,SQL Server使您的主键成为群集键 - 但如果需要,您可以更改它。另外,请注意:构成聚类键的列将添加到表中每个非聚集索引的每个条目中 - 因此您希望保持聚类键尽可能小。这是因为聚类键将用于执行“书签查找” - 如果您在非聚集索引中找到了一个条目(例如,通过社会安全号码的人),现在您需要抓取整行数据到获取更多详细信息,您需要进行查找,为此,使用群集密钥。
关于什么是一个好的或有用的集群和/或主键有一个很大的争论 - 这里有一些很好的博客文章可以阅读:
马克
答案 3 :(得分:1)
你有几个问题。我会打破其中一些:
创建索引时,我为什么要关心群集与非群集?
有时您会关心行的组织方式。这取决于您的数据以及您将如何使用它。例如,如果您的主键是uniqueidentifier
,则可能不希望它为CLUSTERED
,因为GUID值基本上是随机的。这将导致SQL在整个表中随机插入行,从而导致页面拆分,从而损害性能。如果您的主键值总是按顺序递增(例如int IDENTITY
),那么您可能希望它为CLUSTERED
,因此您的表格将始终在最后增长。
默认情况下,主键为CLUSTERED
,大部分时间您都不必担心。
有人告诉我,非聚集索引的插入和删除速度很慢,因为树需要“重建”。我认为Clustered索引不会以这种方式影响性能吗?
实际上,情况恰恰相反。 NONCLUSTERED
索引作为单独的数据结构保留,但该结构旨在允许进行一些修改而无需“重新构建”。最初创建索引时,您可以指定FILLFACTOR
,它指定在索引的每个页面上保留多少可用空间。这允许索引在需要页面拆分之前容忍一些修改。即使必须进行页面拆分,它也只会影响相邻页面,而不会影响整个索引。
相同的行为适用于CLUSTERED
索引,但由于CLUSTERED
索引存储实际的表数据,因此对索引的页面拆分操作可能要昂贵得多,因为可能需要移动整行(而不仅仅是关键列和ROWID
索引中的NONCLUSTERED
。
以下MSDN页面讨论了FILLFACTOR
和页面拆分:
http://msdn.microsoft.com/en-us/library/aa933139(SQL.80).aspx
主键与群集唯一索引有什么特别之处? 约束如何与索引不同?
对于这两者我认为更多的是宣布你的意图。当您调用某个PRIMARY KEY
时,您声明它是识别给定行的主要方法。 PRIMARY KEY
物理上与CLUSTERED UNIQUE INDEX
不同吗?我不确定。行为基本相同,但使用您的数据库的人可能不清楚您的意图。
关于约束,存在许多类型的约束。对于UNIQUE CONSTRAINT
,除了声明您的意图之外,它与UNIQUE INDEX
之间并没有真正的区别。还有其他类型的约束不直接映射到索引类型,例如CHECK
约束,DEFAULT
约束和FOREIGN KEY
约束。
答案 4 :(得分:0)
我没有时间深入回答这个问题,所以这里有一些信息:
你是关于聚簇索引的。他们根据聚集索引的排序顺序重新排列物理数据。您可以专门针对范围限制的查询使用聚簇索引(例如,在日期之间)。
默认情况下,PK是聚类的,但它们不一定是。这只是一个默认设置。 PK应该是该行的UID。
约束可以作为索引实现(例如,唯一约束),但也可以实现为默认值。