跳到主要内容

字符类型

PostgreSQL 的常用字符类型有 text、varchar(n)(或 character varying(n))和 char(n)(或 character(n))。它们都保存文本,主要差异在长度约束和空白填充,而不是“能不能存中文”。

三种类型对比​

类型长度规则尾部空格典型用途
text不声明最大长度原样保存说明、文章、可变长度名称
varchar(n)最多 n 个字符不自动填充有明确业务上限的文本
char(n)固定长度语义写入时补空格,比较时通常忽略少数固定宽度编码

在 PostgreSQL 中,text 和不带长度的 varchar 在存储和性能上通常没有实际差异。长度约束只有在业务规则需要由数据库强制执行时才有意义。

字符数、字节数和编码​

varchar(n) 的 n 表示字符数,不是字节数。数据库编码通常为 UTF-8,一个中文字符可能占多个字节,但仍只计一个字符:

SELECT length('数据库'), octet_length('数据库');

length 返回字符数,octet_length 返回字节数。应用层还可能按 grapheme cluster(用户感知的字符)计数;emoji 和组合字符的显示长度不一定等于 PostgreSQL 的字符数。

长度限制与空值​

CREATE TABLE users (
user_id bigint PRIMARY KEY,
display_name varchar(80) NOT NULL,
bio text,
CHECK (length(trim(display_name)) > 0)
);

varchar(80) 超出长度时会报错(显式转换和赋值的细节应按目标版本测试),而 text 不提供长度上限。长度限制不能替代内容校验:邮箱格式、用户名保留字和 Unicode 规范化仍需单独处理。

NULL 表示未知或缺失,'' 是长度为零的字符串。NOT NULL 只禁止 NULL,不会禁止空字符串;需要禁止空白文本时使用 CHECK。

char(n) 的陷阱​

SELECT length('A '::char(3));
SELECT 'A'::char(3) = 'A '::char(3);

char(n) 会补齐空格,取值或连接时又常被去除尾部空格,容易造成展示和比较上的意外。固定宽度协议字段通常可用 char(n),但国家代码、货币代码等更常用 char(2)/char(3) 配合约束或字典表;普通名称不要使用它。

排序、大小写和区域设置​

字符比较和排序受数据库排序规则(collation)影响。大小写不敏感不是 text 的内建属性,可以使用 lower 生成索引或 citext 扩展:

CREATE INDEX users_email_lower_idx ON users (lower(email));

SELECT * FROM users
WHERE lower(email) = lower($1);

排序规则升级可能改变索引顺序,跨环境迁移前应确认 locale 和 ICU 版本。不要用 lower 猜测所有语言的大小写规则。

模式匹配与索引​

LIKE 'prefix%' 在合适的排序规则和索引配置下可能使用 B-tree;包含任意位置通配符('%part%')通常需要 trigram 等专用索引:

CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX users_name_trgm_idx ON users USING gin (display_name gin_trgm_ops);

索引表达式必须与查询表达式一致。对用户输入拼接 % 时,应同时处理转义,防止把用户输入误当作通配符。

文本类型选择​

  1. 没有可靠上限时用 text,把业务校验放在 CHECK 或应用层。
  2. 有明确且稳定的最大字符数时用 varchar(n)。
  3. 只有协议或遗留格式确实要求定长时使用 char(n)。
  4. 不要为了性能把长文本强行改成 varchar(n);两者性能差异通常来自索引、查询和 TOAST,而非类型名字。