用在字段(列)上的数据类型,核心原则是必须是在磁盘上有明确存储表示的类型。因此,PostgreSQL 的伪类型(Pseudo-Types),如 anyelement、trigger、internal 等,绝对不可以用作字段类型,它们仅用于定义函数参数或返回值。
排除伪类型后,可用在字段上的数据类型及具体要求如下。
🔢 数值类型#
| 类型 | 存储/范围 | 核心要求与说明 |
|---|---|---|
smallint | 2字节,-32768 至 +32767 | 范围最窄,仅在磁盘空间极度敏感时使用 |
integer | 4字节,-2147483648 至 +2147483647 | 最常用的整数类型,在范围、存储和性能间平衡最佳 |
bigint | 8字节,约 ±9.22×10¹⁸ | 仅在 integer 范围不足时使用,性能略低于 integer |
numeric(p, s) | 变长,精确 | p(精度)最大 1000;s(标度)范围 -1000 到 1000;金额等精确计算必选,但运算速度慢 |
real | 4字节,不精确 | 约 6 位十进制有效数字,仅用于可接受舍入误差的科学计算 |
double precision | 8字节,不精确 | 约 15 位十进制有效数字,精度高于 real,仍不精确 |
serial / bigserial | 语法糖 | 自动创建序列并设置 DEFAULT nextval(...),不是真正的独立类型,底层是 integer / bigint |
numeric的精度与标度:p是总有效位数,s是小数点后的位数。NUMERIC(8, 2)表示总共 8 位数字,其中小数点后 2 位,因此整数部分最多 6 位。如果存入的值标度大于声明值,系统会自动四舍五入到声明的小数位。
📝 字符类型#
| 类型 | 长度要求 | 行为与说明 |
|---|---|---|
varchar(n) | n 必须 > 0 且 ≤ 10,485,760(约 10MB) | 变长,有上限;超长值在显式转换时会被截断而不报错 |
varchar / text | 无长度声明 | 变长,理论上限约 1GB;绝大多数场景的首选,无需强行设定上限 |
char(n) | n 必须 > 0 且 ≤ 10,485,760 | 定长,不足部分用空格填充;char 不带长度等价于 char(1);现代应用极少使用 |
🕒 日期与时间类型#
time、timestamp 和 interval 均支持可选的精度 p,用于控制秒的小数部分位数。
p的取值范围:0 到 6(默认使用微秒精度,即p=6)。date:无精度参数,仅存储年月日。timestamptz:记录“时间点”的首选。它内部以 UTC 存储,显示时按会话时区转换,能正确处理跨时区数据。timestamp:不带时区,存储的是“墙上时钟”字面值,不随时区转换。interval:表示时间间隔,同样支持p来限制秒的小数位精度。
🚀 JSON 类型#
| 类型 | 字段层面的核心要求 |
|---|---|
json | 保留输入文本的精确副本(含空格、键序),不支持索引,查询时需重新解析,性能差。 |
jsonb | 字段首选。二进制分解存储,支持 GIN 索引,查询性能远高于 json。但写入时有转换开销,且不保留键序与空格。 |
jsonb 字段的约束实践:可以在 jsonb 列上使用 CHECK 约束来强制某些键的存在或值的格式。对于高频查询的 jsonb 路径,需要创建表达式索引(如 CREATE INDEX ... ON tbl ((data->>'key')))或对整个列创建 GIN 索引,否则查询将全表扫描。
📦 数组类型#
- 定义语法:在任意可用作字段的基础类型后加
[],如integer[]、text[][]。可以创建内置类型、枚举、复合类型、范围或域的数组。 - 维度与长度:声明时的维度(如
[3][3])和长度仅为文档说明,PostgreSQL 不会强制执行。但插入多维数组时,每个维度的长度必须严格匹配,否则报错。 - 元素类型一致性:一个数组字段中的所有元素必须属于同一种数据类型。
🎯 用户定义类型(字段层面的特殊要求)#
枚举(ENUM)
- 标签长度限制:每个枚举值(标签)的最大长度受编译参数
NAMEDATALEN限制,标准安装下为 63 字节。 - 排序内在性:枚举值按声明顺序排序,这会影响
ORDER BY和范围比较的结果。 - 适用边界:仅适用于封闭、稳定、极少变更的固定值集合(如订单状态)。频繁增删枚举值需要
ALTER TYPE,不适合动态性强的场景。
域(DOMAIN)
域是带约束的基础类型,用于将字段级别的通用约束(如 NOT NULL、CHECK)集中管理。
- 可附加的约束:
NOT NULL/NULL、CHECK (expression)以及DEFAULT默认值。 - 约束检查时机:域上的
NOT NULL和CHECK约束在值被转换为域类型时进行检查。 - 字段可用性:域完全可以作为字段类型使用,它是将业务规则抽象到类型层面的有效手段(例如定义一个
email_address域,自带格式校验CHECK约束)。
范围(RANGE) 与 复合(COMPOSITE)
int4range、daterange、tstzrange 等范围类型,以及通过 CREATE TYPE ... AS (...) 定义的复合类型,都可以直接用作字段类型,无额外字段级限制。范围类型用于高效表达连续区间,复合类型用于将多个相关属性打包为一个逻辑单元。
💎 快速核对清单#
| 你需要确保的事 | 对应要求 |
|---|---|
| 绝不使用伪类型建列 | anyelement、trigger、internal、record(仅函数上下文)等均不可作为字段类型 |
| 金额计算 | 用 numeric(p, s),p ≤ 1000,s 在 -1000 ~ 1000 |
| 字符串 | 默认用 text 或 varchar;若用 varchar(n),n ≤ 10,485,760 |
| 时间点 | 优先 timestamptz;需要秒的小数位精度时,p 在 0 ~ 6 |
| JSON | 默认 jsonb;高频查询路径必须配套 GIN 或表达式索引 |
| 数组 | 维度/长度声明不强制,但插入时维度必须匹配 |
| 枚举 | 标签长度 ≤ 63 字节(标准安装);仅用于稳定封闭的集合 |