【数据库知识】PGSQL数据类型详细说明

PGSQL数据类型详细说明

PostgreSQL 数据库数据类型详细说明

PostgreSQL 提供了丰富的数据类型,覆盖数值、字符、日期时间、布尔、二进制、复杂结构等多种场景,支持自定义类型和扩展。以下是按类别整理的详细说明,包含定义、存储特性、取值范围、使用示例注意事项

一、数值类型

用于存储整数、小数、高精度数值等,支持精确计算和近似计算。

1. 整数类型

类型 别名 存储大小 取值范围 描述
smallint int2 2字节 -32768 ~ 32767 小范围整数
integer int/int4 4字节 -2147483648 ~ 2147483647 常用整数(默认整数类型)
bigint int8 8字节 -9223372036854775808 ~ 9223372036854775807 大范围整数
serial serial4 4字节 1 ~ 2147483647 自增整数(等价于 integer + 序列)
bigserial serial8 8字节 1 ~ 9223372036854775807 大范围自增整数(等价于 bigint + 序列)

示例

sql 复制代码
-- 创建自增ID表(serial自动关联序列)
CREATE TABLE users (
  id serial PRIMARY KEY,  -- 等价于 id integer NOT NULL DEFAULT nextval('users_id_seq')
  age smallint CHECK (age > 0),  -- 小范围整数(年龄)
  score bigint  -- 大范围整数(积分)
);

-- 插入数据(id自动生成)
INSERT INTO users (age, score) VALUES (25, 10000000000);

2. 任意精度数值类型

类型 别名 存储大小 描述
numeric decimal 可变(最大131072位数字,16383位小数) 高精度小数,适合财务、货币计算(无精度损失),语法:numeric(precision, scale)

参数说明

  • precision:总位数(1~1000,默认1000)
  • scale:小数位数(0~precision,默认0)

示例

sql 复制代码
-- 创建财务表(精确到分)
CREATE TABLE orders (
  id serial PRIMARY KEY,
  amount numeric(10, 2)  -- 总10位,小数2位(最大99999999.99)
);

INSERT INTO orders (amount) VALUES (12345678.90);  -- 正确
INSERT INTO orders (amount) VALUES (123456789.12);  -- 错误(总位数超过10)

3. 浮点类型(近似计算)

类型 别名 存储大小 取值范围(近似) 精度损失 描述
real float4 4字节 ±1.18×10⁻³⁸ ~ ±3.4×10³⁸ 6位小数 单精度浮点数
double precision float8 8字节 ±2.23×10⁻³⁰⁸ ~ ±1.8×10³⁰⁸ 15位小数 双精度浮点数(默认浮点类型)

注意 :浮点类型存在舍入误差,不适合财务等精确计算 ,优先用 numeric

示例

sql 复制代码
CREATE TABLE sensors (
  id serial PRIMARY KEY,
  temperature real,  -- 单精度(如传感器读数)
  pressure double precision  -- 双精度(如气压)
);

INSERT INTO sensors (temperature, pressure) VALUES (36.5, 1013.25);

二、字符类型

用于存储文本数据,支持定长、变长和无长度限制类型。

1. 定长字符类型

类型 存储大小 描述
char(n) n字节(不足补空格) 定长字符串,n为长度(1~10485760),超出截断,适合固定长度数据(如身份证号)

示例

sql 复制代码
CREATE TABLE products (
  code char(8) PRIMARY KEY,  -- 定长8位编码(如"PROD1234")
  name varchar(50)
);

INSERT INTO products (code, name) VALUES ('ABC12345', '商品A');  -- code存储为'ABC12345'(8位,无空格)
INSERT INTO products (code, name) VALUES ('AB', '商品B');  -- code存储为'AB      '(补6个空格)

2. 变长字符类型

类型 别名 存储大小 描述
varchar(n) character varying(n) 变长(实际长度+1或4字节 overhead) 最大n个字符(n≤10485760),超出报错,适合长度有限的文本(如用户名)
text - 变长(实际长度+1或4字节 overhead) 无长度限制的可变字符串,适合长文本(如文章内容)

注意varchar(n)text 性能接近,优先用 text(更简洁);varchar 不带长度时等价于 text

示例

sql 复制代码
CREATE TABLE articles (
  id serial PRIMARY KEY,
  title varchar(100),  -- 标题(最长100字符)
  content text  -- 正文(无长度限制)
);

INSERT INTO articles (title, content) VALUES (
  'PostgreSQL 数据类型',
  'PostgreSQL 提供丰富的类型...'
);

三、日期时间类型

用于存储日期、时间、时间戳及时间间隔,支持时区处理。

1. 日期与时间

类型 存储大小 格式示例 描述
date 4字节 2024-05-20 日期(年-月-日)
time [without time zone] 8字节 15:30:45 时间(时:分:秒,无时区)
time with time zone 12字节 15:30:45+08 带时区的时间(如北京时间+08)
timestamp [without time zone] 8字节 2024-05-20 15:30:45 时间戳(日期+时间,无时区)
timestamp with time zone 8字节 2024-05-20 15:30:45+08 带时区的时间戳(存储为UTC,显示时转换为本地时区,推荐用此类型)

常用函数

  • current_date:当前日期(如 2024-05-20
  • current_time:当前时间(带时区)
  • current_timestamp:当前时间戳(带时区)
  • now():等价于 current_timestamp

示例

sql 复制代码
CREATE TABLE events (
  id serial PRIMARY KEY,
  event_name varchar(100),
  start_time timestamp with time zone,  -- 带时区的时间戳
  duration interval  -- 时间间隔(如'2 hours 30 minutes')
);

INSERT INTO events (event_name, start_time, duration) VALUES (
  '产品发布会',
  now(),  -- 当前时间戳(带时区)
  '2 hours'  -- 间隔2小时
);

2. 时间间隔类型

类型 存储大小 格式示例 描述
interval 16字节 1 year 2 months 3 days 4 hours 5 minutes 6 seconds 时间间隔,支持年、月、日、时、分、秒等单位,可进行加减运算(如 timestamp + interval

示例

sql 复制代码
SELECT now() + interval '1 day 3 hours';  -- 当前时间加1天3小时
-- 结果:2024-05-21 18:30:45+08(假设当前是2024-05-20 15:30:45+08)

四、布尔类型

类型 存储大小 取值 描述
boolean 1字节 true/false/null 布尔值,也可用 yes/no/on/off 代替(不区分大小写)

示例

sql 复制代码
CREATE TABLE tasks (
  id serial PRIMARY KEY,
  task_name varchar(100),
  completed boolean DEFAULT false  -- 默认未完成
);

INSERT INTO tasks (task_name, completed) VALUES ('学习PostgreSQL', true);

五、二进制类型

类型 存储大小 描述
bytea 可变(最大1GB) 存储二进制数据(如图片、文件),支持转义字符串(如 \x1234abcd)或十六进制前缀(0x1234abcd

示例

sql 复制代码
CREATE TABLE files (
  id serial PRIMARY KEY,
  file_name varchar(100),
  content bytea  -- 存储文件二进制内容
);

-- 插入二进制数据(示例:插入一个简单文本文件的二进制)
INSERT INTO files (file_name, content) VALUES (
  'test.txt',
  E'\\x546573742066696C6520636F6E74656E74'  -- 十六进制表示的"Test file content"
);

六、复杂类型

PostgreSQL 支持数组、复合类型、范围类型等复杂结构,满足多样化数据存储需求。

1. 数组类型

  • 定义 :用 类型[] 表示一维数组,类型[][] 表示二维数组(最多支持多维)。
  • 存储:可变长度,元素类型需一致。
  • 构造 :用 ARRAY[元素1, 元素2]'{元素1,元素2}'::类型[]

示例

sql 复制代码
CREATE TABLE students (
  id serial PRIMARY KEY,
  name varchar(50),
  scores integer[]  -- 成绩数组(如一学期多门课成绩)
);

-- 插入数组数据
INSERT INTO students (name, scores) VALUES (
  '张三',
  ARRAY[90, 85, 95]  -- 等价于 '{90,85,95}'::integer[]
);

-- 查询数组元素(第2门课成绩)
SELECT name, scores[2] FROM students WHERE id = 1;  -- 结果:85

-- 数组函数:array_length(数组, 维度)
SELECT array_length(scores, 1) FROM students;  -- 结果:3(数组长度)

2. 复合类型

  • 定义 :用 CREATE TYPE 创建自定义结构体,包含多个字段。
  • 使用:可直接作为表列类型,或作为函数返回值。

示例

sql 复制代码
-- 创建复合类型(表示人员信息)
CREATE TYPE person AS (
  name varchar(50),
  age integer,
  email varchar(100)
);

-- 创建表使用该类型
CREATE TABLE employees (
  id serial PRIMARY KEY,
  info person  -- 复合类型列
);

-- 插入数据(用ROW构造复合类型值)
INSERT INTO employees (info) VALUES (
  ROW('李四', 30, 'lisi@example.com')  -- 等价于 (name=>'李四', age=>30, email=>'lisi@example.com')
);

-- 查询复合类型字段
SELECT (info).name, (info).age FROM employees;  -- 结果:李四 | 30

3. 范围类型

用于表示连续的数值、日期等范围(如价格区间、日期区间),支持包含、重叠等操作。

类型 描述 示例范围值
int4range 整数范围 [1, 10)(含1不含10)
numrange 数值范围(numeric) (3.14, 9.8]
tsrange 时间戳范围(无时区) [2024-01-01 00:00, 2024-12-31 23:59]
daterange 日期范围 [2024-05-01, 2024-05-31]

示例

sql 复制代码
CREATE TABLE promotions (
  id serial PRIMARY KEY,
  discount numrange,  -- 折扣范围(如[0.8, 0.9)表示8折到9折)
  active_period daterange  -- 活动日期范围
);

-- 插入范围数据(用'[)'表示左闭右开)
INSERT INTO promotions (discount, active_period) VALUES (
  '[0.8, 0.9)',
  '[2024-06-01, 2024-06-30]'
);

-- 查询范围是否重叠
SELECT * FROM promotions WHERE active_period && '[2024-06-15, 2024-07-15]'::daterange;

七、JSON 类型

用于存储 JSON 数据,支持两种类型:

类型 存储方式 描述
json 文本存储 存储原始 JSON 字符串,不验证格式,查询时需解析,性能较低
jsonb 二进制存储 解析并验证 JSON 格式,支持索引(GIN索引),推荐优先使用

常用操作

  • 插入:'{"name": "Alice", "age": 25}'::jsonb
  • 提取字段:jsonb_extract_path_text(column, 'name')column->>'name'
  • 条件查询:WHERE column @> '{"age": 25}'::jsonb(包含指定键值对)

示例

sql 复制代码
CREATE TABLE users (
  id serial PRIMARY KEY,
  profile jsonb  -- 存储用户资料(JSON格式)
);

-- 插入JSON数据
INSERT INTO users (profile) VALUES (
  '{"name": "Bob", "hobbies": ["reading", "coding"], "address": {"city": "Beijing", "zip": "100000"}}'::jsonb
);

-- 查询爱好包含"coding"的用户
SELECT id, profile->>'name' AS name 
FROM users 
WHERE profile->'hobbies' ? 'coding';  -- 结果:Bob

-- 创建GIN索引加速JSON查询
CREATE INDEX idx_profile ON users USING GIN (profile);

八、其他常用类型

1. UUID 类型

类型 存储大小 描述
uuid 16字节 存储通用唯一标识符(UUID),格式如 a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11,推荐用 gen_random_uuid() 生成

示例

sql 复制代码
CREATE EXTENSION IF NOT EXISTS pgcrypto;  -- 启用pgcrypto扩展(提供UUID生成函数)

CREATE TABLE devices (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),  -- 自动生成UUID
  name varchar(100)
);

INSERT INTO devices (name) VALUES ('传感器A');

2. 网络地址类型

类型 存储大小 描述
inet 7~19字节 IPv4/IPv6 地址(含子网掩码),如 192.168.1.1/24
cidr 7~19字节 IPv4/IPv6 子网(CIDR表示法),如 192.168.1.0/24
macaddr 6字节 MAC 地址(如 08:00:2b:01:02:03

示例

sql 复制代码
CREATE TABLE servers (
  id serial PRIMARY KEY,
  ip inet,
  subnet cidr,
  mac macaddr
);

INSERT INTO servers (ip, subnet, mac) VALUES (
  '192.168.1.100/24',
  '192.168.1.0/24',
  '08:00:2b:01:02:03'
);

3. 枚举类型(Enum)

用户自定义的离散值集合,确保字段值只能是预设选项之一。

示例

sql 复制代码
-- 创建枚举类型(表示订单状态)
CREATE TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'delivered');

CREATE TABLE orders (
  id serial PRIMARY KEY,
  status order_status DEFAULT 'pending'
);

INSERT INTO orders (status) VALUES ('paid'), ('shipped');
-- INSERT INTO orders (status) VALUES ('invalid');  -- 报错(值不在枚举中)

PostgreSQL 场景化数据类型选择指南

PostgreSQL 数据类型的选择需结合业务场景特性 (如数据精度、长度、变化频率)、性能需求 (存储效率、查询速度)和数据完整性 (约束、唯一性)。以下按常见业务场景分类,给出针对性选型建议,附推荐类型、理由、示例代码避坑指南

一、用户信息场景(姓名、手机号、邮箱等)

场景特点

  • 数据长度有限(姓名通常≤50字符,手机号11~15位,邮箱≤254字符);
  • 需支持模糊查询(如按姓名搜索)、唯一性约束(如手机号唯一);
  • 避免存储冗余空格,注重可读性。

推荐数据类型

字段 推荐类型 理由 示例代码
姓名 varchar(50) 变长存储(避免定长补空格),长度覆盖绝大多数姓名(含复姓、少数民族名) CREATE TABLE users (id serial, name varchar(50) NOT NULL);
手机号 varchar(15) 支持国际区号(如+86 13800138000),变长灵活;不用char(补空格影响查询) ALTER TABLE users ADD COLUMN phone varchar(15) UNIQUE;
邮箱 varchar(254) 遵循RFC标准(邮箱最大长度254字符),变长存储 ALTER TABLE users ADD COLUMN email varchar(254) UNIQUE CHECK (email LIKE '%@%');
性别 enumchar(1) 枚举类型(enum)限制取值(如'm'/'f'/'u'),char(1)更简洁(如'男'/'女'用'M'/'F') CREATE TYPE gender AS ENUM ('male', 'female', 'unknown'); ALTER TABLE users ADD COLUMN gender gender;

避坑指南

  • ❌ 不用 text 存储手机号/邮箱:text 无长度限制,可能因误操作存入超长无效数据(如手机号输成20位);
  • ❌ 不用 int 存储手机号:国内手机号含前导0(如010-xxxxxxx),且国际号码有+号,整数会丢失符号;
  • ✅ 加唯一约束:UNIQUE 确保手机号/邮箱不重复(如 phone varchar(15) UNIQUE)。

二、财务/交易场景(金额、价格、积分等)

场景特点

  • 精确计算(无舍入误差),避免浮点精度丢失(如0.1+0.2≠0.3);
  • 金额通常有固定小数位(如人民币2位,美元2位);
  • 需支持大额数值(如企业级交易可能超千万)。

推荐数据类型

字段 推荐类型 理由 示例代码
金额(人民币) numeric(12,2) 总12位(含2位小数),最大9999999999.99(百亿级),精确无误差 CREATE TABLE orders (id serial, amount numeric(12,2) NOT NULL CHECK (amount >= 0));
积分 bigint 积分可能超千万(如用户长期积累),bigint 范围(-9e18~9e18)足够 ALTER TABLE users ADD COLUMN points bigint DEFAULT 0;
汇率 numeric(10,6) 汇率通常保留6位小数(如1美元=6.897500人民币),numeric 精确存储 CREATE TABLE exchange_rates (currency varchar(3), rate numeric(10,6));

避坑指南

  • ❌ 绝对不用 float/double precision:浮点类型存在舍入误差(如 0.1::float8 * 3 结果可能为0.30000000000000004),导致财务对账错误;
  • ✅ 加约束:CHECK (amount >= 0) 确保金额非负,CHECK (scale(rate,6) = rate) 限制汇率小数位;
  • ✅ 索引优化:对高频查询的金额字段(如 amount > 1000)建B-tree索引。

三、日志/文本存储场景(操作日志、文章内容、评论)

场景特点

  • 文本内容长度差异大(日志可能几百字,文章可能几万字);
  • 需支持全文检索(如搜索日志关键词);
  • 写入频繁,读取相对较少(日志场景)。

推荐数据类型

字段 推荐类型 理由 示例代码
操作日志 text 无长度限制,变长存储,适合长日志(如错误堆栈) CREATE TABLE operation_logs (id serial, content text, created_at timestamptz);
文章内容 text + tsvector text 存储正文,tsvector 类型配合全文索引(GIN)加速搜索 ALTER TABLE articles ADD COLUMN search_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED; CREATE INDEX idx_article_search ON articles USING GIN(search_vector);
短评论 varchar(500) 限制长度(避免刷屏),变长存储 ALTER TABLE comments ADD COLUMN content varchar(500) NOT NULL;

避坑指南

  • ❌ 不用 char(n) 存储日志/文章:定长会浪费大量存储空间(如100字日志用 char(1000) 会补900空格);
  • ✅ 全文检索优化:用 tsvector 类型存储分词结果,配合 GIN 索引(查询速度提升10倍以上);
  • ✅ 分区表:日志表按时间分区(如按月),避免单表过大影响查询性能。

四、JSON/半结构化数据场景(用户配置、动态表单、API响应)

场景特点

  • 数据结构不固定(如用户自定义配置项);
  • 需支持嵌套字段查询(如 config->'theme'->>'color');
  • 高频读写,需兼顾存储效率和查询性能。

推荐数据类型

字段 推荐类型 理由 示例代码
用户配置 jsonb 二进制存储(比 json 省空间),支持索引(GIN)、字段校验、高效查询 CREATE TABLE user_configs (user_id int, config jsonb NOT NULL); CREATE INDEX idx_config_theme ON user_configs USING GIN ((config->'theme'));
动态表单 jsonb 存储表单字段(如 {"fields": [{"name":"age","type":"number"}]} ALTER TABLE forms ADD COLUMN schema jsonb;

避坑指南

  • ❌ 不用 json 存储高频访问数据:json 是文本存储,查询时需解析,性能比 jsonb 低50%+;
  • ✅ 用 jsonb_path_ops 索引:对JSON字段的键值对查询(如 config @> '{"theme":"dark"}')用 GIN(jsonb_path_ops) 索引更高效;
  • ✅ 加约束:用 CHECK (jsonb_typeof(config) = 'object') 确保JSON为对象类型(非数组/字符串)。

五、唯一标识场景(主键、订单号、设备ID)

场景特点

  • 需全局唯一(避免分布式系统ID冲突);
  • 不希望暴露业务增长(如自增ID可被猜测订单量);
  • 需支持分布式生成(如多服务实例同时生成ID)。

推荐数据类型

字段 推荐类型 理由 示例代码
主键ID uuid 全局唯一(128位),随机生成(如 gen_random_uuid()),不暴露业务量 CREATE EXTENSION IF NOT EXISTS pgcrypto; <br> CREATE TABLE orders (id uuid PRIMARY KEY DEFAULT gen_random_uuid(), ...);
订单号 varchar(32) + uuid 订单号需可读性(如含日期前缀),用 uuid 生成唯一部分(如 ORDER_${to_char(now(),'YYYYMMDD')}_${substr(gen_random_uuid()::text,1,8)} `ALTER TABLE orders ADD COLUMN order_no varchar(32) UNIQUE DEFAULT 'ORDER_'
设备ID macaddr 存储MAC地址(如 08:00:2b:01:02:03),专用类型校验格式 CREATE TABLE devices (id serial, mac macaddr UNIQUE, ...);

避坑指南

  • ❌ 不用 serial 作为分布式系统主键:serial 依赖单实例序列,分布式环境下可能冲突;
  • ✅ 用 uuid-ossp 扩展:除 pgcrypto 外,uuid-ossp 提供更多UUID生成方式(如 uuid_generate_v1() 基于时间戳);
  • ✅ 索引优化:uuid 主键默认建B-tree索引,查询效率与 integer 接近(因UUID随机分布,插入时索引分裂略多,可接受)。

六、时间序列场景(传感器数据、监控指标、日志时间戳)

场景特点

  • 数据按时间顺序写入(高频写入,如每秒数千条);
  • 需支持时间范围查询(如"近1小时数据")、聚合(如"每小时平均值");
  • 数据量大(可能达TB级),需高效压缩和分区。

推荐数据类型

字段 推荐类型 理由 示例代码
时间戳 timestamptz(带时区) 存储UTC时间,显示时自动转换本地时区,避免时区混乱(如跨地域服务器) CREATE TABLE sensor_data (id serial, device_id int, value numeric(10,2), ts timestamptz DEFAULT now());
时间范围 tstzrange(带时区范围) 表示连续时间段(如设备在线时段 [2024-05-20 08:00, 2024-05-20 18:00] ALTER TABLE device_status ADD COLUMN online_period tstzrange;

优化策略

  • 分区表 :按时间分区(如按天/周),用 PARTITION BY RANGE (ts),查询时仅扫描目标分区;
  • 列式存储 :用 timescaledb 扩展(PostgreSQL时序数据库插件),压缩率提升90%+,聚合查询提速100倍;
  • BRIN索引:对时间序列字段建BRIN索引(块范围索引),适合按时间范围查询(索引体积仅为B-tree的1/100)。

七、枚举/状态场景(订单状态、用户等级、开关标志)

场景特点

  • 字段取值固定(如订单状态:待支付/已支付/已发货);
  • 需限制非法值(如不允许"已支付"改为"待支付");
  • 可读性优先(代码中直接用枚举名而非数字)。

推荐数据类型

字段 推荐类型 理由 示例代码
订单状态 enum 类型 自定义枚举(如 order_status),取值固定,插入非法值时报错 CREATE TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'delivered'); ALTER TABLE orders ADD COLUMN status order_status DEFAULT 'pending';
开关标志 boolean 简单二值(如 is_active),存储1字节,查询效率高 ALTER TABLE users ADD COLUMN is_active boolean DEFAULT true;

避坑指南

  • ❌ 不用 varchar 存储枚举值:易出现拼写错误(如"paid"写成"payed"),且无约束;
  • ✅ 枚举扩展:如需新增状态(如"退货中"),用 ALTER TYPE order_status ADD VALUE 'returning' AFTER 'delivered';(PostgreSQL 10+支持);
  • ✅ 状态流转约束:用触发器或应用层逻辑限制状态变更(如"已发货"不能直接改回"待支付")。

八、通用选择原则总结

  1. 精确优先于近似 :财务用 numeric,不用 float;计数用 integer/bigint,不用 real
  2. 长度明确用定长,否则用变长 :身份证号(18位)用 char(18),姓名用 varchar(50),长文本用 text
  3. 唯一标识用 uuid:避免自增ID暴露业务量,支持分布式生成。
  4. JSON用 jsonb :二进制存储+索引支持,优于 json 文本存储。
  5. 时间用 timestamptz:带时区避免跨地域混乱,配合分区/BRIN索引优化时序查询。
  6. 枚举用 enum 类型:限制取值,提升可读性和完整性。

通过以上场景化选型,可在数据准确性、存储效率、查询性能 间取得平衡,为业务系统奠定坚实的数据基础。实际应用中需结合具体业务调整(如超高频写入场景可考虑列式存储扩展),并通过 EXPLAIN ANALYZE 验证查询性能。

相关推荐
I'm a winner2 小时前
【FreeRTOS实战】互斥锁专题:从理论到STM32应用题
数据库·redis·mysql
java_logo2 小时前
Supabase Postgres Docker 容器化部署指南
运维·docker·postgresql·容器·postgres部署教程·postgres部署文档·docker postgres
北邮刘老师2 小时前
马斯克的梦想与棋盘:空天地一体的智能体互联网
数据库·人工智能·架构·大模型·智能体·智能体互联网
开开心心_Every2 小时前
优化C盘存储:自定义软件文档保存路径工具
java·网络·数据库·typescript·word·asp.net·excel
醉舞经阁半卷书12 小时前
Etcd服务端参数详解
数据库·etcd
gugugu.2 小时前
Redis持久化机制详解(一):RDB全解析
数据库·redis·缓存
暗之星瞳3 小时前
mysql表的链接
大数据·数据库·mysql
陌路203 小时前
redis持久化篇AOF与RDB详解
数据库·redis·缓存
@老蝴3 小时前
MySQL - 索引
数据库·mysql