首页 / PostgreSQL 入门教程 / 字符类型

PostgreSQL 入门教程

字符类型

本教程共 50 篇 · 第 12 篇 · 更新于 2026-07-31 · 约 7 分钟阅读

PostgreSQLPostgreSQL 入门教程字符类型varcharchartext

12. 字符类型

本节目标:学完能分清 char、varchar、text,知道日常该用哪个存字符串。

存文字要用字符类型。PostgreSQL 主要提供三种:charvarchartext。名字像,差别却不小。我刚学的时候也以为 char 更快、更省事,结果被定长补空格坑过一次。先把三者区别讲透,再告诉你怎么选。

三种类型一览

类型写法特点
定长char(n) / character(n)固定长度,不足补空格
变长有上限varchar(n) / character varying(n)最长 n 个字符,不补空格
变长无限text / varchar(不带 n)任意长度

char(n) 是定长。存入比 n 短的字符串,它会在右边补空格凑够长度;查询显示时也带这些空格。比如存 'ok'char(4),实际存的是 'ok '

varchar(n) 是变长,只限制「最长 n 个字符」。超出长度直接报错,这是它有别于 text 的关键。

text 不限长度,和「不带长度参数的 varchar」基本是一回事。

实际看看区别

CREATE TABLE demo (
  a CHAR(4),
  b VARCHAR(10),
  c TEXT
);

INSERT INTO demo VALUES ('ok', 'hello', '这是一段很长的文本,text 照单全收');

a 塞超过 4 个字符会报错:

INSERT INTO demo (a) VALUES ('hello');
-- ERROR: value too long for type character(4)

varchar(10) 超过 10 个字符同样报错。text 则随便塞,没有上限烦恼(当然磁盘还是会满)。

Tip

PostgreSQL 里这三种类型性能几乎没差别。不像某些数据库,char(n) 并不会更快,反而定长补空格常常带来麻烦。大多数情况用 textvarchar(n) 即可。

补空格的坑

char(n) 补的空格会在比较时「作祟」。下面两种写法结果可能和你预期不一样:

SELECT 'ok'::char(4) = 'ok' AS eq1;   -- true,比较时忽略尾部空格
SELECT 'ok'::char(4) = 'ok  ' AS eq2; -- true,尾部空格被忽略

但你如果和 text 拼接或按字节处理,空格就显现出来了。比如取长度:

SELECT length('ok'::char(4));  -- 4,因为补了两个空格
SELECT length('ok'::text);     -- 2

所以除非你确实要定长语义(比如固定长度的国标编码),否则别用 char(n)

长度相关的几个点

varchar(n) 的 n 是「字符数」不是「字节数」。一个中文汉字算 1 个字符,但可能占 3 个字节。所以 varchar(10) 能存 10 个汉字,也能存 10 个英文字母。

想看字符串长度用 length,想看字节数用 octet_length

SELECT length('你好'), octet_length('你好');  -- 2, 6(UTF-8 下每个汉字 3 字节)

排序和比较还受「排序规则(collation)」影响,比如是否区分大小写、是否按拼音。一般沿用库默认即可,特殊需求可指定。下面用 "C"(按字节序,任何系统都内置)演示;真实的中文排序规则名取决于操作系统装了哪些 locale,常见如 zh_CN.utf8,可用 \dC 查看本机有哪些:

CREATE TABLE t (name VARCHAR(50) COLLATE "C");

该用哪个

  1. 需要数据库帮你「拦住超长字符串」→ 用 varchar(n),比如用户名、邮箱。这样超长输入会直接报错,由应用层捕获。
  2. 长度完全自由 → 用 text,比如备注、文章内容、日志。
  3. 几乎不需要用 char(n)。除非你确实想要定长补空格的语义,否则它只会白白占空间、还可能引入空格比较的怪问题。

拿我们的 users 表举例:

CREATE TABLE users (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  username VARCHAR(50) NOT NULL,   -- 限制长度
  email VARCHAR(120),
  age SMALLINT,
  created_at TIMESTAMPTZ DEFAULT now()
);
Note

varchar 不带长度时和 text 等价;char 不带长度时等价于 char(1),这点容易踩坑,写的时候别省那个 n。想写变长就显式写 text,意图更清楚。

Tip

char(n) 还有个隐蔽坑:比较时会忽略尾部空格。比如某列是 char(4),存了 'AB ',你写 WHERE code = 'AB' 居然能匹配上,因为末尾空格被无视了。这会让「按精确值更新」悄悄改到不该改的行。我之前就踩过:用 char(2) 存省份简称,结果 '京 ''京' 被判相等,统计时把两条并成一条。所以除非明确要定长语义,否则一律用 varchartext

到底该听谁的

新手常纠结「varchar 和 text 到底选哪个」,结论其实很轻松:两者底层一样,按「要不要限制长度」来选就行。varchar(n) 的价值是那道长度防线——超过 n 就报错,应用层直接拿到异常,不会把超长脏数据写进库。而 text 把长度完全交给你自己控制,适合留言、简介这类没上限的内容。

所以别再为性能纠结,它们没差别。也别为了「省事」全用 text 而丢了 varchar(n) 的约束价值。该限长的限长,不该限长的放开,这就是全部取舍。

排序规则与比较

字符串怎么排、怎么比,由「排序规则(collation)」决定。默认沿用数据库创建时的设置。它影响 ORDER BY 的结果,也影响大小写是否敏感。

CREATE TABLE t (name VARCHAR(50) COLLATE "C");

如果你希望某列不区分大小写比较,可以指定对应 collation,或在查询里转小写后再比。

存储与性能的真相

很多人担心 textvarchar(n) 慢,其实在 PostgreSQL 里两者底层存储几乎一样,都是变长结构。区别只在 varchar(n) 多了一道「长度上限」检查。真正影响性能的是索引设计、数据量和查询写法,不是选 text 还是 varchar

Note

超长的 text(几 MB 的文章)会触发 TOAST 机制,超出阈值的内容被压缩存到表外,对主表行影响不大。所以存长文本用 text 没心理负担。

顺手记几个通用字符串函数:length() 取字符数、substring() 截取、upper()/lower() 大小写、trim() 去空格、position() 找位置,对任意字符类型都适用。

长度参数的意义

varchar(n) 的 n 是「约束」不是「性能优化」。它存在的价值是帮你挡住不合规格的数据,而不是让存储变快。所以:

  • 有明确业务上限(手机号 11 位、用户名 50 字符)→ 写上 n,当一道防线。
  • 长度完全不定(文章、评论)→ 直接用 text,别硬编一个大 n。

总结一句:日常优先 textvarchar(n),把 char(n) 留在真正需要定长的少数场景。