sql主键和索引

Posted

技术标签:

【中文标题】sql主键和索引【英文标题】:sql primary key and index 【发布时间】:2010-10-02 12:37:21 【问题描述】:

假设我在数据库中有一个 ID 行 (int) 设置为主键。如果我经常查询 ID,是否还需要对其进行索引?还是它是主键意味着它已经被索引了?

我问的原因是因为在 MS SQL Server 中我可以在这个 ID 上创建一个索引,正如我所说的,这是我的主键。

编辑:一个额外的问题 - 额外索引主键有什么害处吗?

【问题讨论】:

【参考方案1】:

您是对的,SQL Server 允许您在相同字段上创建重复索引令人困惑。但您可以创建另一个并不表示 PK 索引也不存在。

额外的索引没有好处,但唯一的危害(非常小)是额外的文件大小和行创建开销。

【讨论】:

未使用索引的损坏确实是非常有害的。一方面,索引会占用存储空间。另一方面,它会减慢写入和更新速度。始终删除不会使用的索引。【参考方案2】:

正如其他人已经说过的,主键是自动索引的。

仅当您需要优化使用主键和其他一些特定列的查询时,在主键列上创建更多索引才有意义。通过在主键列上创建另一个索引并包含其他一些列,您可能会达到查询所需的优化。

例如,您有一个包含许多列的表,但您只查询 ID、名称和地址列。以 ID 为主键,我们可以创建如下索引,该索引是建立在 ID 之上的,但包含 Name 和 Address 列。

CREATE NONCLUSTERED INDEX MyIndex
ON MyTable(ID)
INCLUDE (Name, Address)

所以,当你使用这个查询时:

SELECT ID, Name, Address FROM MyTable WHERE ID > 1000

SQL Server 只会使用您创建的索引为您提供结果,它不会从实际表中读取任何内容。

【讨论】:

【参考方案3】:

注意:此答案涉及企业级开发in-the-large

这是一个 RDBMS 问题,而不仅仅是 SQL Server,其行为可能非常有趣。一方面,虽然主键自动(唯一)索引很常见,但它不是绝对的。 有时不能对主键进行唯一索引。

在大多数 RDBMS 中,如果主键不存在,则会自动在主键上创建唯一索引。因此,您可以在将主键列声明为主键之前在主键列上创建自己的索引,然后当您应用主键声明时,数据库引擎将使用该索引(如果可接受)。通常,您可以创建主键并允许创建其默认唯一索引,然后在该列上创建自己的备用索引,然后删除默认索引。

现在是有趣的部分——你什么时候不想要一个唯一的主键索引?当您的表获取足够的数据(行)以使索引的维护过于昂贵时,您不想要也不能容忍一个。这取决于硬件、RDBMS 引擎、表和数据库的特性以及系统负载。但是,它通常会在表格达到几百万行时开始显现。

本质问题是每次插入行或更新主键列都会导致索引扫描以确保唯一性。随着表的增长,唯一索引扫描(或其在任何 RDBMS 中的等效项)变得更加昂贵,直到它主导了表的性能。

我已经多次处理过这个问题,涉及的表有 20 亿行、8 TB 的存储空间以及每天 4000 万行插入。我的任务是重新设计所涉及的系统,其中包括实际上作为第一步删除唯一主键索引。事实上,在我们甚至接近重新设计之前,为了从中断中恢复,在生产中删除该索引是必要的。重新设计包括寻找其他方法来确保主键的唯一性并提供对数据的快速访问。

【讨论】:

如果键是 int 或 bigint 自增键怎么办?在这种情况下,SQL Server 是否足够智能以不进行唯一索引扫描? @quillbreaker:IDENTITY 字段不保证是唯一的。毕竟,如果用户使用IDENTITY_INSERT,用户可以插入重复值。 我知道这是一个古老的话题,但我不明白一个索引的唯一性扫描会对系统造成如此大的负担。 B+tree 扫描应该是 O(log n) * v 其中 v 是索引碎片、不完美树平衡等的约束开销。因此 20 亿行将是 2,000,000,000 次(约 31 次搜索)次的 log base 2,例如, 2 个或 3 个甚至 10 个。每天 40M 插入约为 462/秒,每个插入约 100 IO ......啊......哦。我知道了。这是在广泛使用 SSD 之前。 除非您放弃唯一性约束,否则检查每一行是否唯一性的开销会更大吗?【参考方案4】:

默认情况下,主键总是被索引。

您可以使用 SQL Server Management Studio 或 Transact-SQL 在 SQL Server 2012 中定义主键。创建主键会自动创建相应的唯一、聚集或非聚集索引。

http://technet.microsoft.com/en-us/library/ms189039.aspx

【讨论】:

【参考方案5】:

这里是MSDN的一段话:

当您为表指定 PRIMARY KEY 约束时,数据库引擎会通过为主键列创建唯一索引来强制数据唯一性。此索引还允许在查询中使用主键时快速访问数据。因此,选择的主键必须遵循创建唯一索引的规则。

【讨论】:

【参考方案6】:

除非您指定非聚集,否则 PK 将成为聚集索引

【讨论】:

【参考方案7】:

声明PRIMARY KEYUNIQUE 约束会导致SQL Server 自动创建索引。

可以在不匹配约束的情况下创建唯一索引,但如果没有唯一索引,则不能存在约束(主键或唯一)。

从这里开始,约束的创建将:

导致创建同名索引 拒绝删除创建的索引,因为没有它就不允许存在约束

同时删除约束将删除关联的索引。

那么,PRIMARY KEYUNIQUE INDEX 之间是否有实际区别:

NULL 值不允许出现在 PRIMARY KEY 中,但允许出现在 UNIQUE 索引中;就像在集合运算符(UNION、EXCEPT、INTERSECT)中一样,这里的NULL = NULL 意味着您只能有一个值,因为两个NULLs 被发现是彼此重复的; 每个表只能存在一个PRIMARY KEY,而999可以创建唯一索引 当PRIMARY KEY约束被创建时,它被创建为聚集,除非表上已经有聚集索引或者在其定义中使用了NONCLUSTERED;当UNIQUE索引被创建时,它被创建为NONCLUSTERED,除非它不是特定的CLUSTERED并且这样的已经不存在;

【讨论】:

【参考方案8】:

将其设为主键也应自动为其创建索引。

【讨论】:

【参考方案9】:

在 SQL Server 中,一般来说,主键是自动索引的。 这是真的,但它不能保证更快的查询。 当只有 1 个字段作为主键时,主键将为您提供出色的性能。 但是,当有多个字段作为主键时,索引是基于这些字段的。

例如: 字段 A、B、C 是主键,因此当您根据 WHERE CLAUSE 中的这 3 个字段进行查询时,性能很好, 但是,当您想在 WHERE CLAUSE 中仅使用 C 字段进行查询时,您将无法获得良好的性能。因此,要让性能正常运行,您需要手动索引 C 字段。

在大多数情况下,直到您的记录超过 100 万条,您才会发现问题。

【讨论】:

【参考方案10】:

我有一个没有(单独)索引的庞大数据库。

每当我通过主键查询时,出于所有密集目的,结果都是即时的。

【讨论】:

那是因为PK是聚集索引,看你的查询计划【参考方案11】:

自动索引主键

您可以根据您的使用情况使用 pk 创建其他索引

index zip_code, id 如果您经常按 zip_code 和 id 选择可能会有所帮助

【讨论】:

这就是我一直在寻找的答案——“我为什么要创建索引?”

以上是关于sql主键和索引的主要内容,如果未能解决你的问题,请参考以下文章

外键和主键的 Postgres 和索引

SQL server :主键和外键

SQL - 唯一键,主键和外键

如何分清SQL数据库中的主键与外键

oracle 数据库中主键索引和唯一索引有啥区别

请问SQL server 中的主键和外键的作用