CHAR 与 VARCHAR (Postgres) 的索引性能

Let*_*t4U 20 postgresql performance varchar

在这个答案(/sf/ask/36230561/)中,一个评论引起了我的注意:

还要记住,在进行索引比较时,CHAR 和 VARCHAR 之间通常存在很大差异

这是否适用/仍然适用于 Postgres?

我发现 Oracle 上的页面声称这CHAR或多或少是 for 的别名VARCHAR,因此索引性能是相同的,但我在 Postgres 上没有发现任何明确的内容。

a_h*_*ame 30

CHAR并且VARCHAR在 Postgres(和 Oracle)中实现完全相同。使用这些数据类型时速度没有区别。

但是,有一个差异会影响性能:一char列总是填充到定义的长度。因此,如果您定义一列 aschar(100)和一个 asvarchar(100)但每个char(100)列仅存储 10 个字符,则该列使用 100 个字符存储每个值(您存储的 10 个字符加上 90 个空格),而该varchar列仅存储 10 个字符。

将 100 个字符与 100 个字符进行比较会比将 10 个字符与 10 个字符进行比较要慢 - 尽管我怀疑您是否可以在 SQL 查询中实际测量这种差异。

如果你用10个字符长度的同时声明,并始终将存储正好在其中10个字符,那么绝对不会有任何区别(这是真的为Oracle和Postgres)

所以唯一的区别是为char数据类型完成的填充。


还要记住,在进行索引比较时,CHAR 和 VARCHAR 之间通常存在很大差异

当(且仅当)char列定义太宽(即由于填充而浪费空间)时,上述引用成立。如果char列的长度总是被完全使用(所以没有填充发生),那么上面的引用是错误的(至少对于 Postgres 和 Oracle)


在我看来,char数据类型实际上并没有任何实际用途。只需使用varchar(或text在 Postgres 中)并忘记它的char存在。

  • *将 100 个字符与 100 个字符进行比较会比将 10 个字符与 10 个字符进行比较要慢 - 尽管我怀疑您是否可以在 SQL 查询中实际测量这种差异。* – 根据查询除了排序之外还执行什么操作,差异可以是巨大的。这就是 Postgres 9.5 具有新的“缩写键”功能的原因:http://pgeoghegan.blogspot.de/2015/01/abbreviated-keys-exploiting-locality-to.html (4认同)

Eva*_*oll 7

我同意a_horse_with_no_name所说的一切,并且我通常同意 Erwin 的评论建议:

不,char 是低劣的(而且已经过时了)。text 和 varchar 执行(几乎)相同。

元数据

除了一个小例外,我唯一一次使用的char()是当我希望元数据说这必须有 x 字符时。虽然我知道char()只有在输入超过限制时才会抱怨,但我会经常在CHECK约束中防止欠载。例如,

CREATE TABLE foo (
  x char(10) CHECK ( length(x) = 10 )
);
INSERT INTO foo VALUES (repeat('x', 9));
Run Code Online (Sandbox Code Playgroud)

我这样做有几个原因,

  1. char(x)有时被模式加载器推断为固定宽度的列。这可能会对针对固定宽度字符串优化的语言产生影响。
  2. 它建立了一个有意义且易于执行的约定。我可以用一种语言编写一个模式加载器来根据这个约定生成代码。

需要一个我可以这样做的例子,

  1. 两个字母的状态缩写,但因为可以枚举此列表,我通常会使用ENUM.
  2. 车辆识别号码
  3. 型号(固定尺寸)

关于错误

请注意,有些人可能对限制两侧的错误消息不一致感到不舒服,但这并不困扰我

test=# INSERT INTO foo VALUES (repeat('x', 9));
ERROR:  new row for relation "foo" violates check constraint "foo_x_check"
DETAIL:  Failing row contains (xxxxxxxxx ).
test=# INSERT INTO foo VALUES (repeat('x', 11));
ERROR:  value too long for type character(10)
Run Code Online (Sandbox Code Playgroud)

对比 varchar

此外,我认为上述建议非常符合几乎总是使用text的约定。你也问一下varchar(n)我从不使用那个。至少,我不记得上次使用varchar(n).

  • 如果规范有一个我信任的静态宽度字段,我使用char(n)
  • 否则,我使用text哪个有效varchar(无限制)

如果我发现一个规范具有有意义的可变长度文本键并且我相信它具有恒定的最大长度,我也会使用varchar(n)。但是,我想不出任何符合该标准的东西。

补充说明

相关问答: