PostgreSQL 是什么
本节介绍 PostgreSQL 的基本定位、核心特性以及它与编程语言的区别。学完本节,你将理解 PostgreSQL 是什么、它凭什么成为"世界上最先进的开源数据库",以及为什么值得把它作为你的主力数据库。
前置知识
无需前置知识,适合零基础读者。只要你用过电脑、听说过"数据库"这个词,本节就是你的起点。
基础概念
PostgreSQL 是一个开源的对象关系型数据库管理系统(ORDBMS, Object-Relational Database Management System)。它诞生于 1986 年加州大学伯克利分校的 POSTGRES 项目,经过三十多年持续开发,如今由全球开发者社区共同维护。
要理解这个定义,需要拆成三个关键词:
| 关键词 | 含义 | 对使用者的意义 |
|---|---|---|
| 开源(Open Source) | 源码公开,采用 PostgreSQL 许可证(类似 BSD/MIT) | 免费商用、可自由修改、无厂商锁定 |
| 对象关系型(Object-Relational) | 在关系模型基础上支持自定义类型、继承、函数等对象特性 | 能用 SQL 表达更复杂的业务模型 |
| 数据库管理系统(DBMS) | 提供数据存储、查询、事务、权限、备份等完整能力 | 一个软件覆盖从建库到运维的全流程 |
官方对它的一句话定位是:"The World's Most Advanced Open Source Relational Database"(世界上最先进的开源关系型数据库)。这句话并非纯营销——PostgreSQL 在 SQL 标准兼容度、数据类型丰富度、扩展能力上确实长期领先同类开源产品。
在 PostgreSQL 中,有几个术语你需要尽早建立印象:
- 关系(Relation):就是"表"。PostgreSQL 内部把表、索引、视图统称为关系,系统目录里也用这个词。
- 元组(Tuple):就是"一行记录"。在文档和系统视图中,行(Row)与元组(Tuple)经常混用。
- 模式(Schema):数据库内部的命名空间,用于把表分组,类似操作系统里的文件夹。
- 系统目录(System Catalog):PostgreSQL 把自身的元数据(有哪些表、哪些列、哪些用户)也存成表,放在
pg_catalog模式中。 - 集群(Cluster):一个
initdb初始化的数据目录 + 一个正在运行的服务进程,可包含多个数据库。
语法与用法
PostgreSQL 的使用入口是 SQL(Structured Query Language,结构化查询语言)。你通过客户端发送 SQL 语句,服务端解析、执行并返回结果。最基础的交互链路如下:
# 1. 连接到本地 PostgreSQL 服务(默认端口 5432,默认用户 postgres)
psql -h 127.0.0.1 -p 5432 -U postgres -d demo
# 2. 连接成功后会出现提示符,直接输入 SQL
# demo=#-- 3. 查询服务端版本,确认你连的是哪个版本
SELECT version();
-- 4. 查询当前数据库名与当前用户
SELECT current_database(), current_user;
-- 5. 查看数据库里有哪些表
SELECT table_schema, table_name
FROM information_schema.tables
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
ORDER BY table_schema, table_name;SQL 语句的基本骨架由若干子句(Clause)组成,书写顺序固定:
-- 查询语句的通用骨架,[] 内为可选
SELECT column_list -- 要返回哪些列
FROM table_name -- 从哪张表取数
WHERE condition -- 过滤哪些行
GROUP BY column_list -- 按什么分组
HAVING group_condition -- 过滤哪些分组
ORDER BY column_list -- 结果如何排序
LIMIT n; -- 最多返回几行除了标准 SQL,PostgreSQL 还提供psql 元命令(Meta-Command),它们以反斜杠开头,不是 SQL,而是客户端自己的指令:
\? 查看所有元命令帮助
\l 列出所有数据库
\c demo 切换到 demo 数据库
\dt 列出当前模式下的表
\d users 查看 users 表的结构
\dn 列出所有模式
\du 列出所有角色
\q 退出 psql详细说明
开源与许可证
PostgreSQL 采用 PostgreSQL License,这是一个与 BSD/MIT 同类的宽松许可证。它的要点是:
| 许可要点 | 说明 |
|---|---|
| 免费使用 | 商业项目、闭源项目均可免费使用 |
| 可修改分发 | 可以修改源码并分发,但需保留版权声明 |
| 无 copyleft | 你的衍生作品不必开源 |
| 无专利条款风险 | 不像某些许可证附带专利授权限制 |
这与 MySQL 的 GPL/商业双许可、Oracle 的专有许可形成鲜明对比。对企业而言,最直接的好处是:没有按 CPU/核心数计费的风险,也没有因厂商变更许可策略而被迫迁移的风险。
对象关系型:不只是"表 + 行"
传统关系型数据库只认"表、行、列、基本类型"。PostgreSQL 在此之上引入了对象特性:
-- 自定义复合类型(Composite Type),可当作列类型使用
CREATE TYPE address AS (
province TEXT,
city TEXT,
street TEXT
);
CREATE TABLE users (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL,
addr address -- 直接使用自定义类型作为列类型
);
INSERT INTO users (name, addr)
VALUES ('张三', ROW('广东省', '深圳市', '科技园路 1 号'));
-- 用括号访问复合类型的字段
SELECT name, (addr).city AS city FROM users;-- 表继承(Table Inheritance):子表自动继承父表的列
CREATE TABLE events (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE login_events (
user_id BIGINT NOT NULL
) INHERITS (events);
-- 查询父表会默认包含子表的数据
SELECT * FROM events;还有自定义函数与操作符,你可以为新类型定义属于自己的 +、-> 甚至全新的操作符:
-- 定义一个新操作符,计算两个区间的重叠长度
CREATE FUNCTION overlap_len(a INT4RANGE, b INT4RANGE)
RETURNS INT
LANGUAGE SQL IMMUTABLE AS $$
SELECT GREATEST(
0,
LEAST(upper(a) - 1, upper(b) - 1) - GREATEST(lower(a), lower(b)) + 1
);
$$;
CREATE OPERATOR <-> (
LEFTARG = INT4RANGE,
RIGHTARG = INT4RANGE,
FUNCTION = overlap_len
);
SELECT '[1,10]'::int4range <-> '[5,20]'::int4range AS overlap; -- 6此外,PostgreSQL 允许用 C、PL/pgSQL、PL/Python、PL/Perl 等语言编写扩展(Extension),以 CREATE EXTENSION 一键安装。这使得它能在同一个进程内同时承担多种角色——这也是下一节《PostgreSQL 能做什么》的主题。
标准兼容性
PostgreSQL 对 SQL 标准的兼容度在开源数据库中名列前茅,核心标准特性基本全覆盖:
| SQL 标准能力 | PostgreSQL 支持情况 |
|---|---|
| 事务与隔离级别 | 完整支持 READ COMMITTED / REPEATABLE READ / SERIALIZABLE |
| 窗口函数 | 完整支持,含 ROWS / RANGE / GROUPS 帧 |
| 公共表表达式(CTE) | 支持 WITH,含递归 WITH RECURSIVE |
| JSON 支持 | 支持 SQL/JSON 标准(JSON_TABLE 等,PostgreSQL 17+ 完善) |
| 分组集合 | 支持 GROUPING SETS / CUBE / ROLLUP |
| 外键与约束 | 支持 CHECK / EXCLUDE / 延迟约束 |
| MERGE 语句 | PostgreSQL 15+ 支持标准 MERGE |
这意味着你在 MySQL、Oracle、SQL Server 里学到的标准 SQL 知识,大部分可以直接迁移过来;反过来,写过 PostgreSQL SQL 的人通常也能较快适应其他数据库。当然,各家的方言(Dialect)差异依然存在,比如自增列、字符串拼接、日期函数就不统一。
与编程语言的区别
这是初学者最容易混淆的地方。PostgreSQL 不是编程语言,它是数据库系统;SQL 才是你与它对话的语言。
| 对比维度 | PostgreSQL(数据库系统) | 编程语言(PHP、Python、Go 等) |
|---|---|---|
| 本质 | 长期运行的服务进程 + 数据文件 | 一段被执行的代码 |
| 职责 | 存储、检索、保证数据一致性 | 实现业务逻辑、编排流程 |
| 状态 | 有状态,数据持久保存 | 通常无状态,进程结束即消失 |
| 并发 | 内建多用户并发与事务隔离 | 需自行处理并发与锁 |
| 语言 | SQL(声明式) | 命令式 / 函数式 |
| 部署 | 需要初始化、调优、备份 | 随应用部署 |
| 失效影响 | 数据丢失,影响全局 | 单次请求失败 |
关键区别在于声明式(Declarative)与命令式(Imperative):
-- SQL 是声明式的:你描述"要什么",不描述"怎么取"
-- 至于走全表扫描还是索引扫描,由查询优化器决定
SELECT name, email
FROM users
WHERE city = '深圳市' AND created_at >= '2026-01-01';// 编程语言是命令式的:你逐步描述"怎么做"
// 需要自己写循环、判断、累加
$result = [];
foreach ($users as $user) {
if ($user['city'] === '深圳市' && $user['created_at'] >= '2026-01-01') {
$result[] = ['name' => $user['name'], 'email' => $user['email']];
}
}但两者并非割裂。PostgreSQL 支持服务端编程,你可以把逻辑写进数据库,由数据库直接执行,减少网络往返:
-- PL/pgSQL 是 PostgreSQL 内置的过程化语言
CREATE FUNCTION user_level(total_amount NUMERIC)
RETURNS TEXT
LANGUAGE plpgsql IMMUTABLE AS $$
BEGIN
IF total_amount >= 100000 THEN
RETURN '钻石';
ELSIF total_amount >= 10000 THEN
RETURN '黄金';
ELSE
RETURN '普通';
END IF;
END;
$$;
SELECT user_level(50000); -- 黄金为什么选择 PostgreSQL
综合来看,选择 PostgreSQL 的常见理由有以下几条:
| 理由 | 具体说明 |
|---|---|
| 功能完备 | 一个数据库覆盖 OLTP、JSON、全文搜索、地理空间、向量检索等场景 |
| 可靠性高 | 完整的 WAL 日志、崩溃恢复、复制机制,社区口碑"从不丢数据" |
| 扩展性强 | 扩展(Extension)机制让你按需装载能力,而不必更换数据库 |
| 标准兼容 | SQL 标准支持好,知识可迁移、代码可移植 |
| 社区活跃 | 每年一个大版本,全球核心团队 + 数百贡献者,非单一公司控制 |
| 生态成熟 | 云厂商全部支持,ORM、监控、备份工具齐全 |
| 成本可控 | 无许可证费用,云上 RDS 定价通常低于同等商业数据库 |
反过来,PostgreSQL 也并非没有代价:它的默认配置偏保守,需要按硬件调优;单表超大时的运维(VACUUM、膨胀)比某些数据库更需关注;连接数模型是进程模型,高并发短连接场景需要配合 PgBouncer 之类的连接池。这些在后续章节都会展开。
实战示例
下面用一个完整的小案例,把"建库 → 建表 → 插入 → 查询"跑通,让你对 PostgreSQL 的工作方式有直观感受。
# 第 1 步:创建并连接数据库(在 psql 里执行)
createdb -h 127.0.0.1 -U postgres demo
psql -h 127.0.0.1 -U postgres -d demo-- 第 2 步:建表。用 IDENTITY 生成自增主键(PostgreSQL 10+ 的推荐写法)
CREATE TABLE products (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sku TEXT NOT NULL UNIQUE, -- 商品编码,唯一
name TEXT NOT NULL, -- 商品名称
price NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
stock INTEGER NOT NULL DEFAULT 0,
tags JSONB NOT NULL DEFAULT '[]', -- 标签,用 JSONB 存
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 第 3 步:插入三条测试数据
INSERT INTO products (sku, name, price, stock, tags)
VALUES
('SKU-1001', '机械键盘', 399.00, 120, '["数码", "外设"]'),
('SKU-1002', '人体工学椅', 1299.00, 35, '["家具", "办公"]'),
('SKU-1003', '显示器支架', 199.00, 200, '["数码", "配件"]');
-- 第 4 步:查询价格在 200 到 1500 之间的商品,按价格降序
SELECT id, sku, name, price, stock
FROM products
WHERE price BETWEEN 200 AND 1500
ORDER BY price DESC;预期输出:
id | sku | name | price | stock
----+----------+------------+---------+-------
2 | SKU-1002 | 人体工学椅 | 1299.00 | 35
1 | SKU-1001 | 机械键盘 | 399.00 | 120
(2 rows)再进一步,不用改表结构就能直接查 JSONB 字段里的内容:
-- 查询带有 "数码" 标签的商品(@> 是 JSONB 的包含操作符)
SELECT name, tags
FROM products
WHERE tags @> '["数码"]'::jsonb
ORDER BY name; name | tags
------------+--------------------
显示器支架 | ["数码", "配件"]
机械键盘 | ["数码", "外设"]
(2 rows)最后一次数据库层面的验证:
-- 确认版本、当前库、当前用户
SELECT version() AS ver,
current_database() AS db,
current_user AS usr; ver | db | usr
-----------------------------------------+------+----------
PostgreSQL 18.6 on x86_64-pc-linux-gnu | demo | postgres
(1 row)注意事项
- PostgreSQL 是服务端,不是嵌入式库。它必须作为独立进程运行,客户端通过网络或 Unix Socket 连接,这一点与 SQLite 有本质区别。
- 不要用
SELECT *做线上查询。列顺序变化或新增列都会直接影响下游程序,应显式列出所需列。 - 字符串必须用单引号。双引号在 SQL 里表示标识符(表名/列名),写错会报
column "xxx" does not exist。
-- 错误!双引号会被当成列名,而非字符串
SELECT * FROM users WHERE name = "张三";
-- 正确:使用单引号表示字符串字面量
SELECT * FROM users WHERE name = '张三';- 标识符大小写敏感规则容易踩坑。未加双引号的标识符会被折叠为小写,加了双引号则严格区分大小写。
-- 不推荐:加了双引号,之后每次都必须写双引号
CREATE TABLE "Users" ("Id" BIGINT, "Name" TEXT);
-- 推荐:全部小写下划线,永不需要双引号
CREATE TABLE users (id BIGINT, name TEXT);- PostgreSQL 没有
AUTO_INCREMENT关键字,自增应使用GENERATED ... AS IDENTITY或BIGSERIAL。
-- 错误!这是 MySQL 语法,PostgreSQL 不支持
CREATE TABLE t (id BIGINT AUTO_INCREMENT PRIMARY KEY);
-- 正确:PostgreSQL 10+ 推荐的标准写法
CREATE TABLE t (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY);\d这类元命令只在 psql 里有效,写进 SQL 文件或通过驱动执行会报语法错误。- 数据库名、用户名的默认权限模型较严格:新库默认只有属主能建表,跨用户访问需显式
GRANT。
最佳实践
- 优先选择受支持的稳定大版本(当前为 PostgreSQL 18),并保持小版本最新,以获得安全修复。
- 标识符统一小写下划线风格(
user_orders、created_at),避免大小写与保留字问题。 - 主键统一用
BIGINT GENERATED ALWAYS AS IDENTITY,不用SERIAL(SERIAL是历史遗留语法,存在权限与序列归属的坑)。 - 时间列统一用
TIMESTAMPTZ(带时区),不要用TIMESTAMP,避免时区换算带来的隐性 bug。 - 结构化字段用列,半结构化字段用
JSONB,不要把所有东西都塞进一个 JSON 列。 - 金额用
NUMERIC而非FLOAT,FLOAT存在二进制浮点误差。 - 每个库都显式设置
search_path或使用完整限定名,避免对象被错误模式解析。 - 生产环境务必关闭
SELECT *式的全表拉取,把过滤与聚合尽量放在数据库侧完成。
下一节
继续学习:PostgreSQL 能做什么