CHAR与VARCHAR(Postgres)的索引性能


16

在这个答案(/programming/517579/strings-as-primary-keys-in-sql-database)中,有一条话引起了我的注意:

还请记住,进行索引比较时,CHAR和VARCHAR之间通常会有很大的差异

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

我发现Oracle上的页面声称CHAR或多或少是别名VARCHAR,因此索引性能是相同的,但是在Postgres上没有确定的定义。

Answers:


24

CHAR并且VARCHAR在Postgres(和Oracle)中实现的方式完全相同。使用这些数据类型时,速度没有差异。

但是,有一个差异可以影响性能:char列始终填充为定义的长度。因此,如果将一列定义为char(100)和,varchar(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存在。


2
将100个字符与100个字符进行比较将比将10个字符与10个字符进行比较要慢-尽管我怀疑您实际上可以在SQL查询中测量这种差异。–根据查询除排序以外的功能,差异可能很大。这就是为什么Postgres的9.5有一个新的“缩写键”功能:pgeoghegan.blogspot.de/2015/01/...
chirlu

6

我同意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));

我这样做有几个原因,

  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)

与...对比 varchar

而且,我认为上述建议与几乎总是使用text的约定非常吻合。你也问varchar(n)我从不使用。至少,我不记得上一次使用varchar(n)

  • 如果规格中有我信任的静态宽度字段,则可以使用char(n)
  • 否则,我会使用text有效varchar(无限制)的方法

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

补充说明

相关问答:


1

PostgreSQL

sales_reporting_db=# create table x (y char(2));
CREATE TABLE
sales_reporting_db=# insert into x values ('Y');
INSERT 0 1
sales_reporting_db=# select '*' || y || '*' from x;
 ?column? 
----------
 *Y*

甲骨文

SQL> create table x ( y char(2));

Table created.

SQL> insert into x values ('Y');

1 row created.

SQL> select '*' || y || '*' from x;

'*'|
----
*Y *

PostgreSQL没有用空格填充。


这只是Postgres中的错觉。试试SELECT pg_column_size(y) FROM x;
dezso

-2

我发现这最有用,并且有3行快速解释:

CHAR(n)VS VARCHAR(N)VS Postgres中的文本

  • 如果要存储一些长度未知的文本,请使用TEXT数据类型。
  • 如果要存储一些长度未知的文本,但知道最大长度,请使用VARCHAR(n)
  • 如果您要存储一些确切长度已知的文本,请使用CHAR(N)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.