我应该使用整数主 ID 吗?

Posted

技术标签:

【中文标题】我应该使用整数主 ID 吗?【英文标题】:Should I use integer primary IDs? 【发布时间】:2010-04-17 21:22:03 【问题描述】:

例如,我总是为 users 表生成一个自动增量字段,但我也在他们的用户名上指定一个唯一索引。在某些情况下,我首先需要获取给定用户名的 userId,然后执行所需的查询,或者在所需的查询中使用 JOIN。这是 2 次访问数据库或 JOIN 与 varchar 索引。

small VARCHAR 索引相比,INT 是否有真正的性能优势?

【问题讨论】:

【参考方案1】:

拥有代理主键有几个优点,包括:

当你在另一个表中有一个外键时,如果它是一个整数,它只占用几个字节的额外空间,并且可以快速连接。如果您使用用户名作为主键,则必须将其存储在两个表中 - 占用更多空间,并且在需要加入时进行比较需要更长的时间。

如果用户希望更改他们的用户名,如果您将其用作主键,您将遇到很大的问题。虽然可以更新主键,但这样做是非常不明智的,并且可能会导致各种问题,因为此键可能已发送到各种其他系统,用于链接,保存在备份中,日志已存档等。您无法轻松更新所有这些地方。

【讨论】:

感谢您的快速回复,在我的系统中,“这是 2 次访问数据库或 JOIN 与 varchar 索引”这种情况经常发生³。我应该坚持使用INT ID吗?如果是,2 次旅行或 JOIN?再次感谢! 使用连接。这将比两次访问数据库要快。连接速度很快——这就是数据库的设计目的。【参考方案2】:

这不仅仅是关于性能。您永远不应该键入有意义的值,原因在其他地方都有详细记录。

顺便说一句,我经常将 int 的类型缩放到表格的大小。当我知道一个表不会超过 255 行时,我使用 tinyint 键,smallint 也是如此。

【讨论】:

【参考方案3】:

除了别人说的,还要考虑表的聚类问题。

例如在 SQL Server 中(可能还有其他供应商),如果主键也用作表的聚集索引(这很常见),则递增整数比其他字段类型更有优势。这是因为输入新行时使用的主键总是大于前一行,这意味着新行可以存储在表的末尾而不是中间(同样的场景可以 使用其他字段类型创建主键,但整数类型更适合自己。

将此与 guid 主键进行比较 - 必须将新行插入到表的中间,因为 guid 是非顺序的,因此插入效率非常低。

【讨论】:

【参考方案4】:

首先,很明显,在小型表上,它对性能没有影响。只有在非常大的表上(多大取决于许多因素),它才会因为以下几个原因而有所不同:

    使用 32 位只会消耗 4 个字节的空间。据推测,您的用户名将超过四个非 Unicode 字符,因此占用超过 4 个字节的空间。使用的空间越多,页面上的数据量就越少,索引越胖,您产生的 IO 就越多。

    您的字符列将需要使用 varchar 而不是 char,除非您强制每个人都拥有相同大小的用户名。这也会对性能和存储产生很小的影响。

    除非您使用二进制排序排序规则,否则系统在比较两个字符串时必须进行相对复杂的匹配。两列是否使用相同的排序规则?对于每个字符,它们的大小写是否相同?匹配方面的大小写和重音规则是什么?等等。虽然这可以快速完成,但在非常大的表中,与匹配整数相比,这需要更多的工作。

我不确定您为什么必须两次访问数据库或加入 varchar 列。为什么您不能在数据库中进行一次访问(创建返回您的新 PK),在该数据库中您加入整数 PK 上的 users 表?

【讨论】:

以上是关于我应该使用整数主 ID 吗?的主要内容,如果未能解决你的问题,请参考以下文章

主键同时具有整数和字符串的左连接

我应该在核心数据中使用字符串而不是整数作为属性类型吗?

我应该使用复合主键来加速 PostgreSQL 中基于时间戳的选择吗?

使用带有本地数据库文件 (Sdf) 的实体框架生成 C# 整数主键

我应该在不需要时将整数解析为 Java 中的字符串吗? [复制]

为啥 PostgreSQL 不使用无符号整数作为 ID?那不会提供两倍的可能记录吗?