smallint 或 character(10) 哪个更有效?

Which is more efficient smallint or character(10)?

我在 table 中存储了 5000 本书,table 包含书名、作者、年份和 ISBN。 现在我正在为书评做一个 table。 哪个更有效或更好的方法是在书籍 table 中为 id 创建一个列,并使用该 id 在评论 table 中存储对书籍的评论,或者使用以字符形式存储的图书的 ISBN 号(10)?

当我说 "efficient" 时,我的意思是 "conserving storage space"。

我想说的是,如果table经过精心设计,添加人工smallint主键在存储方面会更便宜space。

一个smallint占用2个字节,而一个包含ASCII字符的character(10)(即counter-intuitively,一个varlena)将占用14个字节。

在table中,多出的2个字节会被浪费掉,但不要忘记你将在主键列上建立索引。所以索引值实际上会被存储两次:一次在table,一次在index.

为了简单起见,让我们忽略元组 headers 和其他开销。

  • 使用 ISBN 作为主键将每 table 行额外花费 14 个字节。

  • 添加 smallint 主键会向 table 添加两个字节,向索引添加两个字节,总共添加四个字节。

所以添加一个smallint主键应该可以节省space.

您不应忽视对齐问题。所有数据类型都存储在内存地址中,这些地址是某些 2 的幂的倍数。这是处理器架构所要求的。 smallint 通常具有对齐方式 2,character 具有对齐方式 1,而例如 timestamp 具有对齐方式 8。

因此,如果您的 table 定义为

CREATE TABLE book (
   id smallint PRIMARY KEY,
   issue_time timestamp with time zone,
   isbn character(10)
);

那么 table 数据将如下所示:

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | |X|X|X|X|X|X| | | | | | | | | ... (ISBN omitted)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 id    padding     issue_time

该行以8字节边界对齐,从id末尾到issue_time开头的六个字节将是空的“填充字节”。

因此,要充分利用它,您必须考虑定义列的顺序。

为什么这一切在现实中不是很相关:

无论如何,具有 5000 或 10000 个条目的 table 是很小的。

虽然花在优化 space 上的任何东西充其量都是不必要的 micro-optimization。

但是,在计划 table 上可能是一个聪明的想法很容易适得其反: 如果 - 与您的预期不同 - 您想要在 table 中存储 70000 本书,您会发现 smallint 是不够的,即使您允许负数 id。当您必须更改主键的数据类型以及在实时系统中引用它的所有外键时,您将不得不忍受的痛苦将远远超过通过巧妙的优化节省大约 100 KB 所带来的任何乐趣。

通常 - 这取决于。对 int 类型的操作非常快。应该比任何字符类型都快。在 Postgres 中类型 "char" 是 "varchar",而 char(10) 需要 11 个字节,这比整数的 4 个多。在二手 isbn 是必填字段,ids 可能是可选的 - 所以没有 ids 的 table 可以更小。

所以 int 是比 varchar 更有效的主键类型。但是在今天的机器上,您需要对可能超过 100 万行的数据进行大量复杂的操作才能找到任何可见的差异。