跳转到主要内容

12 文本类型

存储和比较文本,测量字符长度,并理解填充和排序规则。

PostgreSQL 有三种字符类型:text(无界)、varchar(n)(可变长度,最多 n 个字符)和 char(n)(固定 n 个字符,以空格填充)。对于几乎所有使用场景,text 都是正确的选择。PostgreSQL 的 text 和 varchar 在性能特征上完全相同——与 MySQL 不同,除非希望让数据库强制执行最大长度,否则限制长度没有任何好处。

本章要点

  • 三种文本类型,以及各自适用的场景
  • 为什么 text 是 PostgreSQL 中的默认选择
  • 长度函数:length、char_length、octet_length
  • 排序规则基础——文本如何排序和比较
  • 编码:PostgreSQL 使用数据库的编码存储文本(通常是 UTF-8)

示例

示例 12.1 文本类型
-- text: unbounded, recommended default
SELECT 'hello'::text AS t, length('hello'::text) AS chars;

-- varchar(n): same as text but enforces max length
SELECT 'hi'::varchar(10) AS v, length('hi'::varchar(10)) AS chars;

-- char(n): fixed length, padded with spaces
SELECT 'ab'::char(5) AS c, length('ab'::char(5)) AS chars, '|' || 'ab'::char(5) || '|' AS padded;

-- char_length vs octet_length on multibyte text
SELECT char_length('café') AS chars, octet_length('café') AS bytes;

-- A taste of collation: byte-order sort
SELECT * FROM (VALUES ('apple'), ('Banana'), ('cherry')) AS t(name)
ORDER BY name COLLATE "C";

text 是最常用的文本类型。它可以存储任意长度的字符串,也是大多数应用列应该使用的类型。在内部,PostgreSQL 以相同方式存储 text 和 varchar,对大值使用 TOAST(超长属性存储技术),从而让主表保持紧凑。

varchar(n) 就是在 text 上增加了长度检查。只有在确实有理由限制长度时才使用它(例如需要与某个要求使用这种类型的系统集成)。不带长度的 varchar 与 text 完全相同。

char(n) 是历史遗留的定长类型。它在存储时用空格将值填充到 n 的长度,并在某些操作中去掉这些空格,因此会带来意外。除非有非常具体的理由(例如需要与要求定长编码的系统对接),否则应避免使用 char(n)。

运行示例

运行方式:

$ psql -f source/text-types.sql postgres
   t   | chars
-------+-------
 hello |     5
(1 row)

 v  | chars
----+-------
 hi |     2
(1 row)

   c   | chars |  padded
-------+-------+----------
 ab    |     2 | |ab|
(1 row)
 ...

常见陷阱

  • 出于习惯选择 varchar(255):在 PostgreSQL 中它没有实际用处。请使用 text。如果应用确实需要限制长度,就在应用中或通过 CHECK 约束来强制执行。
  • char(n) 的填充会悄悄改变你的值。'foo'::char(10) 会存储为 'foo '。
  • 多字节字符:length('café') 返回 4(字符数),而 octet_length 返回 5(UTF-8 中的字节数)。根据你要回答的问题选择合适的函数。
  • 排序时的比较取决于数据库的 LC_COLLATE。要按字节顺序排序(通常更快,也更可预测),请使用 COLLATE "C"。
提示

对于不区分大小写的文本列,可以考虑使用 citext 扩展(CREATE EXTENSION citext)——它可以让列级别的 = 和 LIKE 比较不区分大小写,这样查询就不必到处调用 LOWER()。

动手练习

比较长度:SELECT length('x'::text), length('x'::char(3));。两者长度都是 1:length(character) 会忽略末尾填充的空格。使用 octet_length('x'::char(3)) 查看存储的三个字节。然后尝试 SELECT 'foo '::char(6) = 'foo'::char(3);——结果是 true,因为 char 比较会忽略末尾空格。

下载

SQL 文件:text-types.sql · 全部示例文件 · 准备工作