205

我对数据库及其工作原理不是很熟悉。从性能的角度来看(插入/更新/查询)使用字符串作为主键是否比整数慢?

4

15 回答 15

222

从技术上讲是的,但是如果一个字符串作为主键是有意义的,那么你可能应该使用它。这一切都取决于您要为其制作的表的大小以及将成为主键的字符串的长度(更长的字符串 == 更难比较)。对于具有数百万行的表,我不一定会使用字符串,但是通过在较小的表上使用字符串所导致的性能下降量对于使用不具有整数的整数可能是微不足道的与数据无关。

于 2009-02-05T19:44:16.927 回答
87

使用字符串作为主键的另一个问题是,由于索引不断地按顺序排列,当创建一个位于顺序中间的新键时,索引必须重新排序......如果你使用自动number 整数,新键只是添加到索引的末尾。

于 2009-02-05T19:46:42.973 回答
28

插入到具有聚集索引的表中,其中插入发生在序列的中间,不会导致索引被重写。它不会导致包含数据的页面被重写。如果该行所在的页面上有空间,则将其放置在该页面中。单个页面将被重新格式化以将行放置在页面中的正确位置。当页面已满时,将发生页面拆分,页面上的一半行转到一页,另一半转到另一页。然后将页面重新链接到包含具有聚集索引的表数据的页面链接列表中。最多,您将最终编写 2 页的数据库。

于 2012-03-20T23:05:09.647 回答
19

字符串在连接中速度较慢,在现实生活中它们很少是真正唯一的(即使它们应该是)。唯一的好处是,如果您连接到主表只是为了获取名称,它们可以减少连接的数量。然而,字符串也经常会发生变化,从而产生了在公司名称更改或某人结婚时必须修复所有相关记录的问题。这可能会对性能造成巨大影响,并且如果所有应该以某种方式相关的表都不相关(这种情况比您想象的更频繁),那么您也可能存在数据不匹配。从数据完整性的角度和性能的角度来看,在记录的整个生命周期中永远不会改变的整数是一个更安全的选择。自然键通常不利于数据的维护。

我还想指出,两全其美的方法通常是使用自动递增键(或在某些特殊情况下为 GUID)作为 PK,然后在自然键上放置唯一索引。您可以获得更快的连接,不会获得重复的记录,并且您不必因为公司名称更改而更新一百万个子记录。

于 2009-02-05T19:54:57.420 回答
10

变数太多。这取决于表的大小、索引、字符串键域的性质......

通常,整数会更快。但是差异会大到足以在乎吗?很难说。

另外,你选择琴弦的动机是什么?数字自动增量键通常也容易得多。是语义吗?方便?复制/断开连接的问题?您在此处的回答可能会限制您的选择。这也让您想起了您忘记的第三个“混合”选项:Guids。

于 2009-02-05T19:45:36.877 回答
10

只要它是唯一的,您使用什么作为主键都没有关系。如果您关心速度或良好的数据库设计,除非您计划复制数据,否则请使用 int,然后使用 GUID。

如果这是一个访问数据库或一些小型应用程序,那么谁真正在乎。我认为我们大多数开发人员将旧的 int 或 guid 放在前面的原因是因为项目有一种在我们身上成长的方式,而你想给自己留下成长的选择。

于 2009-02-05T19:52:09.857 回答
6

在您获得与数据描述的主题一致并且与数据的预期用途完全吻合的简单而合理的设计之前,不要担心性能。然后,如果出现性能问题,您可以通过调整系统来处理它们。

在这种情况下,使用字符串作为自然主键几乎总是更好,前提是您可以信任它。如果它是一个字符串,请不要担心,只要字符串相当短,比如最多 25 个字符。就性能而言,您不会付出高昂的代价。

数据输入人员或自动数据源是否总是为假定的自然键提供值,或者有时会被省略?输入数据是否偶尔出错?如果是这样,如何检测和纠正错误?

指定查询的程序员和交互式用户是否能够使用自然键来获得他们想要的东西?

如果您不能信任自然密钥,请发明一个代理。如果你发明了一个代理,你还不如发明一个整数。然后您必须担心是否向用户社区隐藏代理。一些没有隐藏代理键的开发者开始后悔了。

于 2009-02-06T19:33:40.940 回答
4

指数意味着很多比较。

通常,字符串比整数长,并且可以应用排序规则进行比较,因此比较字符串通常比比较整数的计算量更大。

但是,有时使用字符串作为主键比与string to numerical id表进行额外连接要快。

于 2009-02-05T19:44:32.870 回答
4

PK 列使用整数的两个原因:

  1. 我们可以为自动递增的整数字段设置标识。

  2. 当我们创建 PK 时,数据库会创建一个索引(集群或非集群),在将数据存储到表中之前对其进行排序。通过在 PK 上使用标识,优化器无需在保存记录之前检查排序顺序。这提高了大表的性能。

于 2014-08-21T12:17:17.710 回答
3

是的,但除非您希望有数百万行,否则不使用基于字符串的键,因为它较慢,通常是“过早的优化”。毕竟,字符串存储为大数字,而数字键通常存储为较小的数字。

但是,需要注意的一件事是,如果您在任何键上都有聚集索引,并且正在执行大量在索引中不连续的插入。写入的每一行都会导致索引重新写入。如果你正在做批量插入,这真的会减慢这个过程。

于 2009-02-05T19:47:28.137 回答
3

您将字符串作为主键的原因是什么?

我只需将主键设置为自动递增的整数字段,并在字符串字段上放置一个索引。

这样,如果您在表上进行搜索,它们应该相对较快,并且您的所有连接和正常查找的速度都不会受到影响。

您还可以控制被索引的字符串字段的数量。换句话说,如果您认为这样就足够了,您可以说“仅索引前 5 个字符”。或者,如果您的数据可以比较相似,您可以索引整个字段。

于 2009-02-05T19:50:42.780 回答
3

从性能的角度来看 - 是的,与使用整数 (PK) 实现的性能相比,字符串 (PK) 会降低性能,其中 PK ---> 主键。

从需求的角度来看-尽管这不是您问题的一部分,但我还是想提一下。当我们处理跨不同表的大量数据时,我们通常会寻找可以为特定表设置的可能的键集。这主要是因为有许多表,并且大多数情况下每个表或某些表将通过某种关系(外键的概念)相互关联。因此,我们真的不能总是选择一个整数作为主键,而是选择 3、4 或 5 个属性的组合作为该表的主键。当我们将记录与其他表关联时,这些键可以用作外键。这使得在需要时将不同表之间的记录关联起来很有用。

因此,为了优化使用 - 我们总是将 1 或 2 个整数与 1 或 2 个字符串属性组合在一起,但仅在需要时才再次使用。

于 2009-02-06T15:18:32.110 回答
3

我可能会使用一个整数作为您的主键,然后将您的字符串(我假设它是某种 ID)作为单独的列。

create table sample (
  sample_pk             INT NOT NULL AUTO_INCREMENT,
  sample_id             VARCHAR(100) NOT NULL,
  ...
  PRIMARY KEY(sample_pk)
);

您始终可以对字符串 (ID) 列(其中 sample_id = ...)进行有条件的查询和连接。

于 2020-09-09T21:06:13.730 回答
2

数据库中的字符串可能存在很大的误解。几乎每个人都认为数字的数据库表示比字符串更紧凑。他们认为 db-s 中的数字在内存中表示。但事实并非如此。在大多数情况下,数字表示更接近于类似字符串的表示。

使用数字或字符串的速度更多地取决于索引而不是类型本身。

于 2009-02-05T20:13:16.367 回答
2

默认情况下,ASPNetUserIds 是 128 个字符的字符串,性能很好。

如果键在中必须是唯一的,则它应该是键。这就是为什么;

主字符串键 = 正确的数据库关系、1 个字符串键(主)和 1 个字符串索引(主)。

另一个选项是典型的 int 键,但如果字符串必须是唯一的,您可能仍然需要添加索引,因为不间断查询以验证或检查其唯一性。

因此,使用int 标识键 = 不正确的数据库关系,1 个 int 键(主),1 个 int 索引(主),可能是唯一的字符串索引,并且不存在手动验证相同的字符串(可能类似于 sql 检查)。

为了在主键的字符串上使用 int 获得更好的性能,当字符串必须是唯一的时,它必须是一个非常奇怪的情况。我一直更喜欢使用字符串键。作为一个好的经验法则,在您需要之前不要对数据库进行非规范化

于 2017-02-21T00:01:34.377 回答