PostgreSQL 能做什么
本节通过具体场景和可运行的 SQL 示例,展示 PostgreSQL 的核心能力边界。学完本节,你将了解它如何用一个数据库同时覆盖事务处理、分析、文档、搜索、地理、时序、队列和向量检索等场景,从而判断哪些需求可以不必再引入其他中间件。
前置知识
阅读本节前,建议先了解:PostgreSQL 是什么
基础概念
PostgreSQL 的独特之处在于它的可扩展架构(Extensible Architecture):数据类型、索引方法、函数语言、外部数据源都可以由扩展(Extension)动态装载,而不需要修改内核。正因如此,同一个 PostgreSQL 实例可以扮演多种角色。
按照工作负载类型,可以把它的能力分为两类:
| 负载类型 | 全称 | 特征 | 典型场景 |
|---|---|---|---|
| OLTP | Online Transaction Processing,联机事务处理 | 大量短小事务、高并发、按主键/索引访问少量行 | 电商下单、账户流水、订单状态流转 |
| OLAP | Online Analytical Processing,联机分析处理 | 少量复杂查询、扫描大量行、聚合与分组 | 报表统计、指标看板、数据仓库 |
| HTAP | Hybrid Transactional/Analytical Processing,混合负载 | 同时承载事务与分析 | 中小规模业务的一体化数据库 |
传统做法是"MySQL 跑 OLTP + 数据同步到 ClickHouse/ES 跑 OLAP"。PostgreSQL 在中小数据规模下可以一套实例兼顾两者,靠的是并行查询、JIT 编译、覆盖索引(Index-Only Scan)、分区裁剪(Partition Pruning)等能力;数据量真正大到单机无法承载时,再考虑拆分。
除事务与分析外,PostgreSQL 还能承担以下角色,这些能力大多以扩展形式提供:
| 能力 | 依赖 | 一句话说明 |
|---|---|---|
| 文档存储 | 内置 JSONB | 像 MongoDB 一样存半结构化数据,且支持事务 |
| 全文搜索 | 内置 tsvector / tsquery | 像 Elasticsearch 一样做分词检索与相关性排序 |
| 地理空间 | PostGIS 扩展 | 像 PostGIS/MongoDB 一样做经纬度、距离、区域计算 |
| 时序数据 | TimescaleDB 扩展 / 内置分区 | 像 InfluxDB 一样存指标、做时间窗口聚合 |
| 消息队列 | LISTEN/NOTIFY + FOR UPDATE SKIP LOCKED | 轻量级任务队列,无需引入 Kafka/RabbitMQ |
| 向量检索 | pgvector 扩展 | 像专用向量库一样做相似度搜索,支撑 RAG |
| 外部数据源 | postgres_fdw / file_fdw | 直接查询其他 PostgreSQL 或 CSV 文件 |
| 定时任务 | pg_cron 扩展 | 在库内调度周期性 SQL |
下面逐项给出最简示例。注意:扩展类能力需要先安装扩展,示例中已标注 CREATE EXTENSION 语句。
语法与用法
要判断某项能力是否可用,可以先查询当前实例已装有哪些扩展:
-- 查看当前数据库中已安装的扩展
SELECT extname, extversion, nspname AS schema_name
FROM pg_extension e
JOIN pg_namespace n ON n.oid = e.extnamespace
ORDER BY extname;
-- 查看当前实例"可安装"的扩展(需先安装扩展包 RPM/DEB)
SELECT name, default_version, comment
FROM pg_available_extensions
ORDER BY name;安装扩展的标准语句:
-- 安装扩展,通常需要超级用户权限
CREATE EXTENSION IF NOT EXISTS pgvector;
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- 升级扩展版本
ALTER EXTENSION pgvector UPDATE;
-- 卸载扩展
DROP EXTENSION pgvector;详细说明
场景一:OLTP 事务处理
这是 PostgreSQL 最核心的用途。它通过多版本并发控制(MVCC, Multi-Version Concurrency Control) 实现"读不阻塞写、写不阻塞读",并支持完整的事务语义。
-- 下单:扣库存 + 建订单,必须在同一个事务内完成
BEGIN;
-- FOR UPDATE 锁定该商品行,防止并发超卖
UPDATE products
SET stock = stock - 1
WHERE sku = 'SKU-1001' AND stock > 0;
INSERT INTO orders (order_no, sku, qty, amount, status)
VALUES ('ORD-20260921-0001', 'SKU-1001', 1, 399.00, 'pending');
COMMIT;-- PostgreSQL 9.5+:UPSERT,存在则更新、不存在则插入
INSERT INTO products (sku, name, price, stock)
VALUES ('SKU-1001', '机械键盘', 379.00, 100)
ON CONFLICT (sku)
DO UPDATE SET price = EXCLUDED.price,
stock = products.stock + EXCLUDED.stock
RETURNING id, sku, price, stock;场景二:OLAP 分析查询
PostgreSQL 支持并行顺序扫描、哈希聚合、窗口函数、分组集合,加上物化视图可以支撑中小规模的分析需求。
-- 按日、按商品分类统计销售额,用窗口函数算占比
SELECT
date_trunc('day', o.created_at) AS stat_date,
p.category,
SUM(o.amount) AS total_amount,
ROUND(
100.0 * SUM(o.amount) / SUM(SUM(o.amount)) OVER (PARTITION BY date_trunc('day', o.created_at)),
2
) AS pct_of_day
FROM orders o
JOIN products p ON p.sku = o.sku
WHERE o.created_at >= now() - INTERVAL '7 days'
AND o.status = 'paid'
GROUP BY 1, 2
ORDER BY 1 DESC, total_amount DESC;-- 分组集合:一次查询同时得到"按分类""按渠道""总计"三层汇总
SELECT
COALESCE(p.category, '(全部)') AS category,
COALESCE(o.channel, '(全部)') AS channel,
SUM(o.amount) AS total_amount
FROM orders o
JOIN products p ON p.sku = o.sku
WHERE o.status = 'paid'
GROUP BY GROUPING SETS ((p.category), (o.channel), ())
ORDER BY category, channel;场景三:JSON 文档存储
JSONB 是二进制存储的 JSON,支持索引、操作符与函数,是"关系 + 文档"混用的关键。JSONB 在 PostgreSQL 9.4+ 提供(JSON 类型在 9.2+,但仅存原文不做解析)。
-- 用 JSONB 存储商品的可变属性,避免频繁改表
CREATE TABLE product_attrs (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sku TEXT NOT NULL UNIQUE,
attrs JSONB NOT NULL DEFAULT '{}'
);
INSERT INTO product_attrs (sku, attrs) VALUES
('SKU-1001', '{"color": "黑色", "switch": "青轴", "wireless": false, "weight_g": 890}'),
('SKU-1002', '{"color": "灰色", "material": "网布", "adjustable": true}')
ON CONFLICT (sku) DO NOTHING;
-- -> 取 JSON 对象字段(返回 JSONB),->> 取文本值
SELECT sku,
attrs ->> 'color' AS color,
attrs ->> 'switch' AS switch_type,
(attrs ->> 'weight_g')::INT AS weight_g
FROM product_attrs
WHERE attrs ? 'switch'; -- ? 判断是否存在该键-- 为 JSONB 建 GIN 索引,加速包含查询
CREATE INDEX idx_product_attrs_gin ON product_attrs USING GIN (attrs);
-- @> 包含:找出所有"无线且青轴"的商品
SELECT sku, attrs
FROM product_attrs
WHERE attrs @> '{"wireless": true, "switch": "青轴"}'::jsonb;场景四:全文搜索
PostgreSQL 内置 tsvector(文档向量)与 tsquery(查询向量),支持词干还原、停用词、权重与相关性排序。中文分词需配合 zhparser 等扩展或使用 simple 配置按字切分。
-- 建全文搜索表,用生成列自动维护 tsvector
CREATE TABLE articles (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title TEXT NOT NULL,
body TEXT NOT NULL,
-- PostgreSQL 12+ 支持 STORED 生成列;18 中默认即为 virtual
search_vec TSVECTOR
GENERATED ALWAYS AS (
setweight(to_tsvector('simple', coalesce(title, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(body, '')), 'B')
) STORED
);
CREATE INDEX idx_articles_search ON articles USING GIN (search_vec);
-- 检索并按相关性排序
SELECT id, title, ts_rank(search_vec, query) AS rank
FROM articles,
to_tsquery('simple', 'postgresql & 索引') AS query
WHERE search_vec @@ query
ORDER BY rank DESC
LIMIT 10;-- pg_trgm 扩展:支持模糊匹配与 LIKE '%...%' 的索引加速
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX idx_articles_title_trgm ON articles USING GIN (title gin_trgm_ops);
-- 相似度匹配,% 是相似度阈值操作符
SELECT title, similarity(title, 'postgres 索引优化') AS sim
FROM articles
WHERE title % 'postgres 索引优化'
ORDER BY sim DESC;场景五:地理空间(PostGIS)
PostGIS 是 PostgreSQL 最著名的扩展之一,提供几何类型、空间索引(GiST/SP-GiST)与数百个空间函数。
CREATE EXTENSION IF NOT EXISTS postgis;
-- 存储门店经纬度,geography 类型以米为单位计算,适合跨经度场景
CREATE TABLE stores (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL,
location GEOGRAPHY(POINT, 4326) NOT NULL
);
INSERT INTO stores (name, location) VALUES
('深圳南山店', ST_SetSRID(ST_MakePoint(113.9304, 22.5333), 4326)::geography),
('深圳福田店', ST_SetSRID(ST_MakePoint(114.0550, 22.5410), 4326)::geography);
CREATE INDEX idx_stores_location ON stores USING GIST (location);
-- 查询 3 公里内的门店,并按距离升序
SELECT name,
ROUND(ST_Distance(location, ST_MakePoint(113.9345, 22.5400)::geography)::NUMERIC, 1) AS distance_m
FROM stores
WHERE ST_DWithin(location, ST_MakePoint(113.9345, 22.5400)::geography, 3000)
ORDER BY distance_m;场景六:时序数据
时序场景不一定要装 TimescaleDB:PostgreSQL 10+ 的声明式分区(Declarative Partitioning) 配合 BRIN 索引,已能支撑相当规模的指标存储。
-- 按月分区存储设备指标
CREATE TABLE metrics (
device_id BIGINT NOT NULL,
ts TIMESTAMPTZ NOT NULL,
cpu_usage REAL NOT NULL,
mem_usage REAL NOT NULL
) PARTITION BY RANGE (ts);
-- 创建 2026 年 9 月与 10 月的分区
CREATE TABLE metrics_2026_09 PARTITION OF metrics
FOR VALUES FROM ('2026-09-01') TO ('2026-10-01');
CREATE TABLE metrics_2026_10 PARTITION OF metrics
FOR VALUES FROM ('2026-10-01') TO ('2026-11-01');
-- BRIN 索引对"按时间递增写入"的数据极其高效,体积仅为 B-tree 的几百分之一
CREATE INDEX idx_metrics_ts_brin ON metrics USING BRIN (ts);
-- 时间窗口聚合,分区裁剪会自动跳过无关分区
SELECT date_trunc('hour', ts) AS hour,
ROUND(AVG(cpu_usage)::NUMERIC, 2) AS avg_cpu,
ROUND(MAX(mem_usage)::NUMERIC, 2) AS max_mem
FROM metrics
WHERE device_id = 1001
AND ts >= '2026-09-01' AND ts < '2026-10-01'
GROUP BY 1
ORDER BY 1;场景七:轻量消息队列
不引入 Kafka 也能做任务队列:SELECT ... FOR UPDATE SKIP LOCKED(PostgreSQL 9.5+)让多个消费者并行抢任务而互不阻塞;LISTEN/NOTIFY 则用于实时通知。
-- 任务表
CREATE TABLE jobs (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
payload JSONB NOT NULL,
status TEXT NOT NULL DEFAULT 'queued', -- queued/running/done/failed
run_at TIMESTAMPTZ NOT NULL DEFAULT now(),
locked_by TEXT,
locked_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_jobs_queue ON jobs (run_at) WHERE status = 'queued';
-- 消费者原子领取一个任务:SKIP LOCKED 跳过别人已锁定的行
WITH job AS (
SELECT id FROM jobs
WHERE status = 'queued' AND run_at <= now()
ORDER BY run_at
LIMIT 1
FOR UPDATE SKIP LOCKED
)
UPDATE jobs j
SET status = 'running', locked_by = 'worker-1', locked_at = now()
FROM job
WHERE j.id = job.id
RETURNING j.id, j.payload;-- LISTEN/NOTIFY:发布-订阅式通知,适合缓存失效、配置热更新
-- 会话 A(订阅方)
LISTEN order_created;
-- 会话 B(发布方)
SELECT pg_notify('order_created', '{"order_no": "ORD-20260921-0001"}');场景八:向量检索(pgvector)
pgvector 扩展让 PostgreSQL 直接存储 embedding 并做相似度检索,是构建 RAG(检索增强生成)应用的常见选择。
CREATE EXTENSION IF NOT EXISTS pgvector;
CREATE TABLE documents (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
content TEXT NOT NULL,
embedding VECTOR(1024) NOT NULL -- 维度需与模型输出一致
);
-- HNSW 索引:近似最近邻检索,查询快、构建慢
CREATE INDEX idx_documents_embedding ON documents
USING hnsw (embedding vector_cosine_ops);
-- <=> 是余弦距离操作符,越小越相似
SELECT id, content, 1 - (embedding <=> '[...]'::vector) AS similarity
FROM documents
ORDER BY embedding <=> '[...]'::vector
LIMIT 5;能力选型速查
| 需求 | 首选方案 | 何时该换专门系统 |
|---|---|---|
| 事务写入 | 内置 | 写入超过单机 IOPS 上限 → 分库分表 |
| 分析报表 | 内置 + 物化视图 | 单表数十亿行且要求亚秒响应 → ClickHouse |
| 文档存储 | JSONB + GIN | 无固定 schema 且写入极密集 → MongoDB |
| 全文搜索 | tsvector + GIN | 需复杂分词/聚合/高亮 → Elasticsearch |
| 地理空间 | PostGIS | 需要全球瓦片服务 → 专用 GIS 平台 |
| 时序 | 分区 + BRIN / TimescaleDB | 千万级/秒写入 → InfluxDB/Timescale |
| 消息队列 | SKIP LOCKED 队列 | 需要跨机房多副本高吞吐 → Kafka |
| 向量检索 | pgvector(HNSW) | 十亿级向量 → Milvus/Qdrant |
实战示例
综合案例:一个"电商商品中心"用同一套表同时支撑事务、文档、搜索与向量推荐。
# 建库并连接
createdb -h 127.0.0.1 -U postgres demo
psql -h 127.0.0.1 -U postgres -d demo-- 第 1 步:安装需要用到的基础扩展
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- 第 2 步:建表 —— 结构化列 + JSONB 属性列 + 全文搜索生成列
CREATE TABLE products (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
sku TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
category TEXT NOT NULL,
price NUMERIC(10, 2) NOT NULL CHECK (price >= 0),
stock INTEGER NOT NULL DEFAULT 0 CHECK (stock >= 0),
attrs JSONB NOT NULL DEFAULT '{}',
search_vec TSVECTOR
GENERATED ALWAYS AS (
setweight(to_tsvector('simple', coalesce(name, '')), 'A') ||
setweight(to_tsvector('simple', coalesce(category, '')), 'B')
) STORED,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- 第 3 步:建三类索引,分别服务 JSONB 查询、模糊搜索、全文检索
CREATE INDEX idx_products_attrs_gin ON products USING GIN (attrs);
CREATE INDEX idx_products_search_gin ON products USING GIN (search_vec);
CREATE INDEX idx_products_name_trgm ON products USING GIN (name gin_trgm_ops);
-- 第 4 步:灌入测试数据
INSERT INTO products (sku, name, category, price, stock, attrs) VALUES
('SKU-1001', '机械键盘', '外设', 399.00, 120, '{"color": "黑色", "wireless": false}'),
('SKU-1002', '人体工学椅', '家具', 1299.00, 35, '{"material": "网布", "adjustable": true}'),
('SKU-1003', '显示器支架', '配件', 199.00, 200, '{"material": "铝合金", "max_load_kg": 9}'),
('SKU-1004', '无线机械键盘', '外设', 559.00, 80, '{"color": "白色", "wireless": true}');-- 第 5 步:建订单表,并用一次事务完成"扣库存 + 建订单"
CREATE TABLE IF NOT EXISTS orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_no TEXT NOT NULL UNIQUE,
sku TEXT NOT NULL REFERENCES products (sku),
qty INTEGER NOT NULL CHECK (qty > 0),
amount NUMERIC(10, 2) NOT NULL CHECK (amount >= 0),
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
BEGIN;
-- 带 stock >= 1 的条件,保证并发下不会扣成负数
UPDATE products SET stock = stock - 1
WHERE sku = 'SKU-1004' AND stock >= 1;
INSERT INTO orders (order_no, sku, qty, amount, status)
VALUES ('ORD-20260921-0001', 'SKU-1004', 1, 559.00, 'paid');
COMMIT;-- 第 6 步:文档式查询 —— 找出"无线"的键盘
SELECT sku, name, price, attrs ->> 'color' AS color
FROM products
WHERE attrs @> '{"wireless": true}'::jsonb
AND name LIKE '%键盘%'; sku | name | price | color
----------+--------------+--------+-------
SKU-1004 | 无线机械键盘 | 559.00 | 白色
(1 row)-- 第 7 步:全文检索 —— 检索词必须与分词结果精确匹配
SELECT sku, name
FROM products
WHERE search_vec @@ to_tsquery('simple', '机械键盘')
ORDER BY name; sku | name
----------+------------
SKU-1001 | 机械键盘
(1 row)注意这里只命中了 SKU-1001,没有命中 SKU-1004(无线机械键盘)。原因正如后文"注意事项"所述:默认解析器把连续的汉字当作一个词元,机械键盘 与 无线机械键盘 是两个不同的词元,因此无法互相匹配。再验证一下:
-- 查询 '键盘' 什么也匹配不到,因为不存在单独的词元 '键盘'
SELECT sku, name
FROM products
WHERE search_vec @@ to_tsquery('simple', '键盘'); sku | name
-----+------
(0 rows)这正是中文全文搜索必须引入 zhparser / pg_jieba 等分词扩展的根本原因。
-- 第 8 步:模糊匹配 —— 输入有错别字也能命中
-- 相似度阈值默认为 0.3;`%` 操作符即"相似度 >= 阈值",走 GIN 索引
SHOW pg_trgm.similarity_threshold;
SELECT sku, name, ROUND(similarity(name, '无线机械健盘')::NUMERIC, 3) AS sim
FROM products
WHERE name % '无线机械健盘'
ORDER BY sim DESC; sku | name | sim
----------+--------------+-------
SKU-1004 | 无线机械键盘 | 0.400
(1 row)pg_trgm 的原理:把字符串切成连续三元组(Trigram)集合,similarity(a, b) 返回"两个集合的交集大小 / 并集大小"。即使输入有错别字,只要大部分三元组仍然相同,相似度就会保持在阈值之上,因此能被 % 命中。值得注意的是,相似度是基于字符的,与语义无关——这正是它与向量检索的本质区别。
-- 全量查看相似度排名,便于理解阈值的作用
SELECT sku, name, ROUND(similarity(name, '无线机械健盘')::NUMERIC, 3) AS sim
FROM products
ORDER BY sim DESC; sku | name | sim
----------+--------------+-------
SKU-1004 | 无线机械键盘 | 0.400
SKU-1001 | 机械键盘 | 0.000
SKU-1002 | 人体工学椅 | 0.000
SKU-1003 | 显示器支架 | 0.000
(4 rows)-- 第 9 步:聚合 —— 按分类看库存与均价,过滤掉库存过低的分类
SELECT category,
COUNT(*) AS sku_count,
SUM(stock) AS total_stock,
ROUND(AVG(price), 2) AS avg_price,
MIN(price) AS min_price,
MAX(price) AS max_price
FROM products
GROUP BY category
HAVING SUM(stock) >= 50
ORDER BY total_stock DESC; category | sku_count | total_stock | avg_price | min_price | max_price
----------+-----------+-------------+-----------+-----------+-----------
配件 | 1 | 200 | 199.00 | 199.00 | 199.00
外设 | 2 | 199 | 479.00 | 399.00 | 559.00
(2 rows)注意"家具"分类(总库存 35)被 HAVING 过滤掉了——这正是 HAVING 与 WHERE 的分工:WHERE 过滤行,HAVING 过滤分组结果。
注意事项
JSONB不是"万能列"。高频过滤、排序、连接的字段应建为普通列;把一切都塞进 JSONB 会丧失约束、统计信息与查询优化能力。
-- 不推荐:把业务关键字段全部塞进 JSONB
CREATE TABLE orders_bad (
id BIGINT PRIMARY KEY,
data JSONB NOT NULL -- order_no、amount、status 全在里面,无法建约束
);
-- 推荐:关键字段建列,附加属性用 JSONB 补充
CREATE TABLE orders (
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
order_no TEXT NOT NULL UNIQUE,
amount NUMERIC(10, 2) NOT NULL CHECK (amount >= 0),
status TEXT NOT NULL DEFAULT 'pending',
extra JSONB NOT NULL DEFAULT '{}'
);JSON与JSONB别混用。JSON保留原始文本(含重复键、空格),每次访问都要重新解析;JSONB解析后二进制存储,支持索引。除非要保留原始格式,否则一律用JSONB。- 全文搜索的中文分词需要额外配置。默认的
simple配置按空白与标点切分,中文会被当成一个整词,需配合zhparser、pg_jieba等扩展。
-- 错误!默认 english 配置会把中文整段当成一个词,几乎搜不到
SELECT to_tsvector('english', '机械键盘手感很好');
-- 结果:'机械键盘手感很好':1 (整段成为一个词元)
-- 正确:装 zhparser 后用中文配置分词
-- CREATE TEXT SEARCH CONFIGURATION chinese (PARSER = zhparser);
SELECT to_tsvector('chinese', '机械键盘手感很好');FOR UPDATE SKIP LOCKED只适合队列,不适合业务加锁。它会让查询"跳过"被锁行,用在库存扣减上会静默漏掉数据。- 分区不是免费的。分区数过多会拖慢规划阶段(Planning Time),建议单表控制在几百到几千个分区以内。
- 扩展需要操作系统层面安装。
CREATE EXTENSION pgvector报 "could not open extension control file" 说明只装了数据库、没装扩展包。 - 向量索引的维度必须与模型一致。
VECTOR(1024)的行插入 768 维向量会直接报错。 LISTEN/NOTIFY不保证持久化。服务重启期间的通知会丢失,不能当作可靠消息队列使用。
最佳实践
- 先用内置能力,再考虑引入扩展。能用标准 SQL 与
JSONB解决的,不要急着装扩展。 - 一个数据库实例承担的职责不宜过多。搜索、向量这类重负载若 QPS 很高,独立实例部署比混布更稳。
- 为
JSONB建 GIN 索引时注意写放大。GIN 索引更新成本高于 B-tree,写入密集的表要评估fastupdate参数(默认on)带来的延迟。 - 全文检索的
tsvector用生成列维护,避免在应用层手写触发器同步。 - 时序数据优先用"分区 + BRIN",只有在需要自动压缩、连续聚合、降采样时才引入 TimescaleDB。
- 队列表要定期归档已完成任务,否则
jobs表会随业务量无限膨胀,拖慢SKIP LOCKED扫描。 CREATE EXTENSION纳入版本管理。把扩展定义写进迁移脚本,避免各环境扩展版本不一致。- 评估"一体化"的真实边界:单机 PostgreSQL 在千万级行、数百 QPS 的规模下表现优异;超过这个量级就该认真考虑拆分,而不是继续堆参数。
下一节
继续学习:发展历史与版本演进