Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 外键或主键上的聚集索引?_Sql_Sql Server_Clustered Index - Fatal编程技术网

Sql 外键或主键上的聚集索引?

Sql 外键或主键上的聚集索引?,sql,sql-server,clustered-index,Sql,Sql Server,Clustered Index,我有一个带有autoinc int主键Id和外键UserId的表Item 我有一个表User,带有autoinc int主键Id 默认情况下,Item.Id的索引是聚集的 我主要是在UserId上查询项目,所以我的问题是:是否最好将UserId外键索引设置为聚集索引?在标识字段上设置聚集索引的优点是,记录将按创建顺序存储。新记录添加到表的末尾 如果使用外键作为聚集索引,则记录将按该顺序存储。当你创建新记录时,数据会被碎片化,因为记录被插入中间,这会降低性能。 如果您想在外键上创建索引,那么只需为

我有一个带有autoinc int主键
Id
和外键
UserId
的表
Item

我有一个表
User
,带有autoinc int主键
Id

默认情况下,
Item.Id
的索引是聚集的


我主要是在
UserId
上查询项目,所以我的问题是:是否最好将
UserId
外键索引设置为聚集索引?

在标识字段上设置聚集索引的优点是,记录将按创建顺序存储。新记录添加到表的末尾

如果使用外键作为聚集索引,则记录将按该顺序存储。当你创建新记录时,数据会被碎片化,因为记录被插入中间,这会降低性能。
如果您想在外键上创建索引,那么只需为其添加非聚集索引。

聚集索引是在主键上创建的,因此您可以做的是将其保留为聚集索引,然后在项的用户Id上创建非聚集索引。这将仍然是非常快的用户。Id列将是聚集索引

可能

item.user id
列是否是item表中唯一的列?如果没有,您需要通过向键添加第二列(可能更多)来将其作为集群主键,以使其唯一/这可能会增加您没有预料到的额外开销

是否与
item.id
列存在任何关系?如果是这样的话,那么这些可能对应用程序的性能很重要,因此应该加以考虑

项.user id
值可能更改的频率是多少?如果根本没有对它有利的话;更新的频率越高,情况就越糟,因为这会导致碎片化


我的建议是,使用常规的
item.id
作为聚集键构建应用程序,稍后在获得一些数据后尝试(在使用生产数据副本的测试系统中)切换聚集索引并测试其影响;这样你就可以很容易地看到真正的结果,而不是试图猜测众多的可能性。这样可以避免过早的优化/确保您做出正确的选择。

通常,您希望在访问频率最高的索引上进行聚类。但是你根本不需要有一个聚类索引。您(或您的DBA)需要评估事物并权衡优缺点,以便选择最合适的索引策略

如果集群在一个单调的计数器上,比如
identity
列,那么所有新行都将插入到表的末尾:这意味着创建了一个“热点”,这可能会导致插入时的锁争用,因为执行插入的每个SPID都会命中相同的数据页

没有集群索引的表将其数据页组织为一个堆,几乎只是一个数据页的链接列表

SQL Server索引是B树。对于非聚集索引,B树的叶节点是指向相应数据页的指针。这意味着,如果使用了索引并且没有覆盖查询的列,则必须进行额外的查找以获取数据页。这意味着额外的I/O和分页


聚集索引是不同的:它们的叶节点本身就是数据页,这意味着堆基本上消失了:表扫描意味着遍历聚集索引的B树。优点是,一旦在聚集索引中找到了所需的内容,您就已经拥有了所需的数据页,从而避免了在非聚集索引上搜索可能需要的额外I/O。当然,缺点是聚集索引更大,因为它携带整个表,所以遍历聚集索引的成本更高。

答案仅取决于使用场景。例如,Guffa宣称数据将被分割。那是错误的。如果您的查询主要依赖于UserId,那么按ItemId聚集的数据对您来说是碎片化的,因为同一用户的项目可能分布在许多页面上

当然,与sequential ItemId(如果在模式中是sequential的话)相比,使用UserId作为集群键会在插入时导致页面分裂。这最多是两次额外的页面写入。但是,当您由某个用户选择时,他的项目可能会分散在数十个页面上(取决于每个用户的项目、项目大小、插入策略等),因此会导致大量页面读取。如果每次插入都有大量这样的选择(非常常用的web/olap场景),那么您可能会面临数百次IO操作,而页面拆分所需的操作为数不多。这就是创建集群索引的目的,而不仅仅是通过代理ID进行集群

所以没有明确的答案,集群用户ID在您的情况下是好是坏,因为这在很大程度上取决于上下文。选择/插入操作之间的比率是多少?如果按itemid进行集群,则用户ID的碎片化程度如何?表中还有多少额外的标记,因为sql server中存在一个陷阱(如下所示)


您可能知道,聚集索引需要唯一的值。这不是一个大问题,因为您可以在对(UserId、ItemId)上创建索引。聚集索引本身并不存储在磁盘上,所以不管有多少字段。但非聚集索引将聚集索引值存储在它们的叶子中。因此,如果在UserId+ItemId上有聚集索引(让我们设想它们的类型是[int],大小是8字节)和在ItemId上有非聚集索引,那么这个索引的大小(每个b树叶8字节)将是作为聚集索引的ItemId(每个叶4字节)的两倍.

您使用的是什么品牌的数据库?不要忘记,在最新版本的SQL Server中,您还可以选择完全覆盖非聚集索引。。。。如果你真的需要两者,你甚至不需要选择。