PostgreSQL架构与索引深度剖析
前言
你维护了一个电商网站,需要存储千万级商品数据,你选了 MySQL。但随着业务发展,产品经理提了各种需求:地理位置搜索、全文检索、JSON 文档存储、时序数据分析...于是你引入了 Redis、Elasticsearch、MongoDB、InfluxDB,原本简单的单体架构变成了复杂的分布式系统。有没有一个数据库能原生支持这些需求?有,它就是 PostgreSQL。
🏠个人主页:你的主页
文章目录
一、PostgreSQL是什么
1.1 一句话定义
PostgreSQL(简称 PG)是一个功能最强大的开源关系型数据库,被称为"数据库天花板"。
1.2 为什么说它是天花板
PG 不仅能完全替代 MySQL,在很多场景下还能替代:
| 场景 | 传统方案 | PG 替代方案 |
|---|---|---|
| 关系型存储 | MySQL | PG 原生支持 |
| 全文搜索 | Elasticsearch | PG + GIN 索引 |
| 文档存储 | MongoDB | PG + JSONB |
| 地理信息 | PostGIS/Redis GeoHash | PG + GiST 索引 |
| 时序数据 | InfluxDB | PG + BRIN 索引 |
| 向量搜索 | Milvus/Pinecone | PG + pgvector 插件 |
一个数据库,多种索引,无限扩展。
1.3 国产数据库的"祖师爷"
PG 完全开源可商用(BSD 协议),国内很多自研数据库都有 PG 的影子:
- 阿里云 PolarDB(兼容 PG)
- 腾讯云 TDSQL-PG
- 华为 GaussDB(基于 PG)
- 人大金仓 KingbaseES(基于 PG)
- 瀚高数据库(基于 PG)
可以说,PG 养活了国内大半数据库团队。
二、存储架构详解
2.1 数据组织方式
PG 将数据组织成类似 Excel 表的结构:
数据库(Database)
└── 模式(Schema)
└── 表(Table)
└── 行(Tuple)
与 MySQL 的区别:
| 概念 | MySQL | PostgreSQL |
|---|---|---|
| 数据库 | Database | Database |
| 模式 | 不支持(或等同于 Database) | Schema(一个 Database 可有多个 Schema) |
| 表 | Table | Table/Relation |
| 行 | Row | Tuple |
PG 多了一层 Schema,可以在同一个数据库内实现更好的逻辑隔离。
2.2 堆表文件
数据表在磁盘上以**堆表文件(Heap File)**的形式存储:
$PGDATA/base/<database_oid>/<relfilenode>
database_oid:数据库的 OIDrelfilenode:表的文件节点号
举个例子:
sql
-- 查看表的存储位置
SELECT pg_relation_filepath('products');
-- 结果:base/16384/16385
2.3 数据页结构
当堆表文件超过 1GB 时,会自动拆分成多个文件(16385、16385.1、16385.2...)。
每个文件由多个 8KB 的数据页组成:
┌─────────────────────────────────────────┐
│ Page Header │ ← 24 字节,页面元信息
├─────────────────────────────────────────┤
│ Item Pointers │ ← 行指针数组,指向实际数据
│ (Line Pointers) │
├─────────────────────────────────────────┤
│ │
│ Free Space │ ← 空闲空间
│ │
├─────────────────────────────────────────┤
│ Tuples │ ← 实际行数据(从页尾向前增长)
│ (Row Data) │
├─────────────────────────────────────────┤
│ Special Space │ ← 特殊空间(索引页使用)
└─────────────────────────────────────────┘
与 MySQL InnoDB 的区别:
| 特性 | MySQL InnoDB | PostgreSQL |
|---|---|---|
| 页大小 | 16KB(默认) | 8KB(默认) |
| 行存储方式 | 聚簇索引(数据存在主键索引叶子节点) | 堆表(数据和索引分离) |
| 主键要求 | 必须有主键(没有会自动生成) | 可以没有主键 |
2.4 MVCC 实现差异
PG 和 MySQL 都支持 MVCC(多版本并发控制),但实现方式完全不同。
MySQL InnoDB 的 MVCC:
原始数据行 → Undo Log(存储旧版本)
- 更新时,旧版本数据写入 Undo Log
- 通过 Undo Log 链回溯历史版本
- Undo Log 会定期清理(Purge)
PostgreSQL 的 MVCC:
原始数据行(标记为删除) + 新数据行(插入)
- 更新时,不修改原数据,而是插入一条新数据
- 原数据标记
xmax(删除事务ID),新数据标记xmin(创建事务ID) - 旧版本数据由 VACUUM 进程清理
打个比方:
- MySQL:像用橡皮擦掉旧内容,写上新内容,旧内容存在草稿纸上
- PG:像在新的一行写新内容,旧的那行划掉但还在
各自的优缺点:
| 特性 | MySQL | PostgreSQL |
|---|---|---|
| 更新性能 | 原地更新,较快 | 插入新行,较慢 |
| 读取性能 | 需要回溯 Undo Log | 直接读取,较快 |
| 空间占用 | Undo Log 可能膨胀 | 表可能膨胀(需要 VACUUM) |
| 回滚速度 | 需要应用 Undo Log | 直接丢弃新行,很快 |
三、索引类型全解析
PG 之所以全能,核心在于它支持多种索引类型,且架构上支持扩展自定义索引。
3.1 B-Tree 索引(默认)
这是最常用的索引类型,适用于等值查询和范围查询。
sql
CREATE INDEX idx_product_price ON products(price);
-- 等值查询
SELECT * FROM products WHERE price = 99;
-- 范围查询
SELECT * FROM products WHERE price BETWEEN 50 AND 100;
PG 的 B-Link Tree vs MySQL 的 B+Tree:
MySQL 使用标准 B+Tree:
[30|60] ← 非叶子节点
/ | \
[10|20] [40|50] [70|80] ← 叶子节点(双向链表)
PG 使用 B-Link Tree(Lehman-Yao 算法):
[30|60] → ← 非叶子节点也有右指针
/ | \
[10|20]→[40|50]→[70|80] ← 叶子节点(单向链表)
B-Link Tree 的优势:
- 非叶子节点有右指针,页分裂时不需要锁整棵树
- 并发性能更好,特别是高并发写入场景
3.2 GIN 索引(全文搜索)
GIN(Generalized Inverted Index,通用倒排索引)适用于全文搜索和数组查询。
原理:将文本分词,建立"词元 → 文档ID"的映射。
文档1: "PostgreSQL 是最强数据库"
文档2: "MySQL 也是数据库"
文档3: "PostgreSQL 支持全文搜索"
分词后建立倒排索引:
┌──────────────┬─────────────┐
│ 词元 │ 文档ID │
├──────────────┼─────────────┤
│ PostgreSQL │ 1, 3 │
│ MySQL │ 2 │
│ 数据库 │ 1, 2 │
│ 全文搜索 │ 3 │
└──────────────┴─────────────┘
使用示例:
sql
-- 创建全文搜索索引
CREATE INDEX idx_product_name_gin ON products USING gin(to_tsvector('chinese', name));
-- 全文搜索
SELECT * FROM products
WHERE to_tsvector('chinese', name) @@ to_tsquery('chinese', '蓝牙 & 耳机');
GIN + JSONB:替代 MongoDB
sql
-- 创建 JSONB 列的 GIN 索引
CREATE INDEX idx_product_attrs ON products USING gin(attributes jsonb_path_ops);
-- 查询 JSON 中包含特定键值对的记录
SELECT * FROM products
WHERE attributes @> '{"color": "blue", "size": "L"}';
JSONB 是 PG 优化后的二进制 JSON 格式,配合 GIN 索引,百万级文档也能毫秒级查询。
3.3 GiST 索引(地理信息)
GiST(Generalized Search Tree,通用搜索树)是一个索引框架,支持多维数据。
R-Tree 原理:
一维数据用线段表示范围,二维数据用矩形表示范围。
┌─────────────────────────┐
│ 根节点矩形 │
└───────────┬─────────────┘
┌─────┴─────┐
↓ ↓
┌─────────┐ ┌─────────┐
│ 矩形A │ │ 矩形B │
└────┬────┘ └────┬────┘
↓ ↓
[点1,点2] [点3,点4]
查询"附近 1 公里的店铺"时:
- 计算查询点周围 1 公里的矩形范围
- 从根节点开始,找与查询矩形相交的子矩形
- 递归向下,最终找到叶子节点的坐标点
使用示例:
sql
-- 启用 PostGIS 扩展
CREATE EXTENSION postgis;
-- 创建地理位置列和索引
ALTER TABLE stores ADD COLUMN location geometry(Point, 4326);
CREATE INDEX idx_store_location ON stores USING gist(location);
-- 查询上海市中心 1 公里内的店铺
SELECT name, ST_Distance(location, ST_SetSRID(ST_MakePoint(121.4737, 31.2304), 4326)) as distance
FROM stores
WHERE ST_DWithin(
location,
ST_SetSRID(ST_MakePoint(121.4737, 31.2304), 4326),
1000 -- 1000米
)
ORDER BY distance;
3.4 BRIN 索引(时序数据)
BRIN(Block Range Index,块范围索引)适用于按时间或 ID 顺序插入的大数据表。
原理:不为每行数据建索引,而是为每批数据页记录范围摘要。
┌─────────────────────────────────────────────────┐
│ 页范围 │ 最小时间 │ 最大时间 │
├────────┼───────────────────┼───────────────────┤
│ 1-128 │ 2025-01-01 00:00 │ 2025-01-15 23:59 │
│ 129-256│ 2025-01-16 00:00 │ 2025-01-31 23:59 │
│ 257-384│ 2025-02-01 00:00 │ 2025-02-15 23:59 │
└────────┴───────────────────┴───────────────────┘
查询 2025-02-10 的数据时,直接定位到 257-384 页范围,跳过其他页。
使用示例:
sql
-- 创建 BRIN 索引
CREATE INDEX idx_logs_created_at ON logs USING brin(created_at);
-- 查询某天的日志
SELECT * FROM logs WHERE created_at BETWEEN '2025-02-10' AND '2025-02-11';
BRIN vs B-Tree 对比:
| 特性 | B-Tree | BRIN |
|---|---|---|
| 索引大小 | 大(每行一个条目) | 极小(每批页一个条目) |
| 查询精度 | 精确 | 粗略(需要扫描范围内的页) |
| 适用场景 | 随机数据 | 顺序插入的数据(时间、自增ID) |
| 维护成本 | 高 | 低 |
打个比方:
- B-Tree 像书的详细目录,精确到每一节
- BRIN 像书的章节目录,只告诉你大概在哪个章节
3.5 Hash 索引
适用于等值查询,不支持范围查询。
sql
CREATE INDEX idx_product_sku ON products USING hash(sku);
-- 只支持等值查询
SELECT * FROM products WHERE sku = 'SKU-12345';
注意:PG 10 之前 Hash 索引不记录 WAL,崩溃后需要重建。PG 10+ 已修复。
3.6 索引类型总结
| 索引类型 | 适用场景 | 可替代的中间件 |
|---|---|---|
| B-Tree | 等值、范围查询 | MySQL |
| GIN | 全文搜索、JSONB、数组 | Elasticsearch、MongoDB |
| GiST | 地理位置、多维数据 | PostGIS、Redis GeoHash |
| BRIN | 时序数据、顺序插入 | InfluxDB |
| Hash | 等值查询 | - |
四、进程架构详解
4.1 多进程 vs 多线程
MySQL:多线程架构
mysqld 进程
├── 连接线程1
├── 连接线程2
├── 连接线程3
└── 后台线程(IO、Purge等)
PostgreSQL:多进程架构
Postmaster(主进程)
├── Backend Process 1(后端进程)
├── Backend Process 2
├── Backend Process 3
└── Background Workers(后台进程)
各自的优缺点:
| 特性 | MySQL(多线程) | PostgreSQL(多进程) |
|---|---|---|
| 内存占用 | 低(线程共享内存) | 高(每个进程独立内存) |
| 稳定性 | 一个线程崩溃可能影响整个进程 | 一个进程崩溃不影响其他进程 |
| 并发连接 | 支持更多连接 | 连接数受限(需要连接池) |
| 上下文切换 | 快 | 慢 |
4.2 Postmaster 主进程
Postmaster 是 PG 的"指挥中心":
-
监听客户端连接请求
-
为每个新连接 Fork 出后端进程
-
监控所有子进程的健康状态
-
管理共享内存
客户端连接请求
↓
Postmaster 接收
↓
Fork 后端进程
↓
后端进程处理请求
4.3 Backend Process 后端进程
每个客户端连接对应一个后端进程(也叫 Postgres 进程)。
bash
# 查看 PG 进程
ps aux | grep postgres
postgres 1234 postgres: user db 127.0.0.1(54321) idle
postgres 1235 postgres: user db 127.0.0.1(54322) SELECT
postgres 1236 postgres: user db 127.0.0.1(54323) UPDATE waiting
问题:如果应用有 500 个连接,就要创建 500 个进程,内存消耗巨大。
解决方案:使用连接池
-
PgBouncer:轻量级连接池,推荐
-
Pgpool-II:功能更丰富,支持负载均衡
应用(500连接) → PgBouncer(连接池) → PostgreSQL(50进程)
4.4 Background Workers 后台进程
PG 有多个后台进程负责维护工作:
| 进程名 | 职责 |
|---|---|
| Background Writer | 持续将脏页写入磁盘,减少 Checkpoint 压力 |
| Checkpointer | 定期将所有脏页强制写入磁盘 |
| WAL Writer | 将 WAL 缓冲区写入磁盘 |
| Autovacuum Launcher | 启动自动 VACUUM 进程 |
| Autovacuum Worker | 执行 VACUUM 清理死元组 |
| Stats Collector | 收集统计信息 |
| Logical Replication | 逻辑复制相关 |
VACUUM 是什么?
前面说过,PG 更新数据时不删除旧行,而是标记为"死元组"。VACUUM 就是清理这些死元组的进程。
sql
-- 手动执行 VACUUM
VACUUM products;
-- VACUUM FULL(重建表,会锁表)
VACUUM FULL products;
-- 查看表的死元组数量
SELECT relname, n_dead_tup FROM pg_stat_user_tables;
与 MySQL 的对比:
| 特性 | MySQL | PostgreSQL |
|---|---|---|
| 旧版本清理 | Purge 线程清理 Undo Log | VACUUM 进程清理死元组 |
| 是否需要手动干预 | 一般不需要 | 大表可能需要调优 VACUUM |
| 表膨胀问题 | 较少 | 可能发生(需要关注) |
五、内存架构详解
5.1 共享内存区域
所有后端进程共享的内存区域:
┌─────────────────────────────────────────────────────┐
│ Shared Memory │
├─────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────┐ │
│ │ Shared Buffer Pool │ │ ← 缓存数据页
│ │ (shared_buffers) │ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ WAL Buffer │ │ ← WAL 日志缓冲
│ │ (wal_buffers) │ │
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ CLOG Buffer │ │ ← 事务状态缓存
│ └─────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Lock Space / Other │ │ ← 锁信息等
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
5.2 Shared Buffer Pool
这是 PG 最重要的内存区域,用于缓存数据页和索引页。
sql
-- 查看 shared_buffers 配置
SHOW shared_buffers;
-- 推荐设置为物理内存的 25%
-- postgresql.conf
shared_buffers = 4GB
工作流程:
后端进程查询数据
↓
检查 Shared Buffer Pool
├── 命中 → 直接返回
└── 未命中 → 从磁盘读取 → 放入 Buffer Pool → 返回
与 MySQL Buffer Pool 的区别:
| 特性 | MySQL InnoDB Buffer Pool | PostgreSQL Shared Buffers |
|---|---|---|
| 默认大小 | 128MB | 128MB |
| 推荐大小 | 物理内存的 50-80% | 物理内存的 25% |
| 为什么 PG 推荐更小? | - | PG 依赖操作系统的文件缓存 |
5.3 进程私有内存
每个后端进程还有自己的私有内存:
| 内存区域 | 用途 | 配置参数 |
|---|---|---|
| work_mem | 排序、哈希操作 | work_mem |
| maintenance_work_mem | VACUUM、CREATE INDEX | maintenance_work_mem |
| temp_buffers | 临时表 | temp_buffers |
sql
-- 查看 work_mem
SHOW work_mem; -- 默认 4MB
-- 大查询可以临时调大
SET work_mem = '256MB';
SELECT * FROM big_table ORDER BY column1;
注意 :work_mem 是每个操作的内存,一个查询可能有多个排序操作,总内存 = work_mem × 操作数 × 连接数。
六、WAL日志机制
6.1 为什么需要 WAL
数据在 Shared Buffer 中更新后,如果还没写入磁盘就崩溃了,数据就丢了。
解决方案:Write-Ahead Logging(预写日志)
- 先写日志,再写数据
- 崩溃后通过日志恢复数据
6.2 WAL 工作流程
1. 事务开始
2. 修改 Shared Buffer 中的数据页
3. 将修改操作写入 WAL Buffer
4. 事务提交时,WAL Buffer 刷入磁盘(WAL 文件)
5. 后台进程异步将脏页刷入磁盘
6. 崩溃恢复时,重放 WAL 日志
为什么先写 WAL 而不是直接写数据页?
- WAL 是顺序写 ,数据页是随机写
- 顺序写磁盘性能是随机写的几十倍
6.3 WAL 文件结构
$PGDATA/pg_wal/
├── 000000010000000000000001
├── 000000010000000000000002
├── 000000010000000000000003
└── ...
每个 WAL 文件默认 16MB。
6.4 与 MySQL Redo Log 的对比
| 特性 | MySQL Redo Log | PostgreSQL WAL |
|---|---|---|
| 文件结构 | 固定大小,循环写入 | 持续增长,归档后删除 |
| 默认大小 | 48MB(2个文件×24MB) | 无上限(可配置保留策略) |
| 用途 | 崩溃恢复 | 崩溃恢复 + 复制 + PITR |
PITR(Point-In-Time Recovery):
PG 可以通过 WAL 归档实现任意时间点恢复:
bash
# 恢复到指定时间点
recovery_target_time = '2025-02-15 14:30:00'
七、查询执行流程
7.1 完整流程
┌─────────────────────────────────────────────────────────────┐
│ Backend Process │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
│ │ Parser │ → │ Analyzer│ → │ Planner │ → │ Executor │ │
│ │ (解析器) │ │ (分析器) │ │ (优化器) │ │ (执行器) │ │
│ └─────────┘ └─────────┘ └─────────┘ └──────┬──────┘ │
│ ↓ │
│ ┌─────────────────┐│
│ │ Access Methods ││
│ │ (访问方法) ││
│ └────────┬────────┘│
└───────────────────────────────────────────────────┼─────────┘
↓
┌──────────────────────────────────┐
│ Shared Memory │
│ ┌────────────┐ ┌────────────┐ │
│ │Buffer Pool │ │ WAL Buffer │ │
│ └────────────┘ └────────────┘ │
└──────────────────────────────────┘
↓
┌──────────────────────────────────┐
│ Disk │
│ ┌────────────┐ ┌────────────┐ │
│ │ Data Files │ │ WAL Files │ │
│ └────────────┘ └────────────┘ │
└──────────────────────────────────┘
7.2 各模块职责
Parser(解析器):
- 检查 SQL 语法是否正确
- 生成解析树(Parse Tree)
Analyzer(分析器):
- 检查表、列是否存在
- 检查权限
- 生成查询树(Query Tree)
Planner/Optimizer(优化器):
- 选择使用哪个索引
- 选择 Join 方式(Nested Loop、Hash Join、Merge Join)
- 生成执行计划(Plan Tree)
Executor(执行器):
- 按执行计划调用 Access Methods
- 返回结果
7.3 查看执行计划
sql
EXPLAIN ANALYZE SELECT * FROM products WHERE price > 100;
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Index Scan using idx_product_price on products (cost=0.29..8.31 rows=1 width=100) (actual time=0.015..0.016 rows=1 loops=1)
Index Cond: (price > 100)
Planning Time: 0.080 ms
Execution Time: 0.030 ms
7.4 Access Methods(访问方法)
Access Methods 是 PG 扩展性的核心,它定义了如何访问不同类型的数据。
Access Methods
├── Heap AM(堆表访问)
├── Index AM(索引访问)
│ ├── B-Tree
│ ├── GIN
│ ├── GiST
│ ├── BRIN
│ └── Hash
└── 自定义 AM(插件扩展)
通过开放 Access Methods 接口,用户可以扩展支持:
- 向量搜索(pgvector)
- 图数据库(Apache AGE)
- 列式存储(Citus)
八、PostgreSQL vs MySQL 深度对比
8.1 架构对比
| 特性 | MySQL | PostgreSQL |
|---|---|---|
| 进程模型 | 多线程 | 多进程 |
| 存储引擎 | 可插拔(InnoDB、MyISAM等) | 单一(堆表) |
| 索引与数据 | 聚簇索引(数据在主键索引中) | 分离(堆表 + 索引) |
| MVCC 实现 | Undo Log | 多版本元组 |
| 连接管理 | 线程池 | 需要外部连接池 |
8.2 功能对比
| 功能 | MySQL | PostgreSQL |
|---|---|---|
| JSON 支持 | JSON(5.7+) | JSONB(更强大) |
| 全文搜索 | 支持(较弱) | 原生支持(GIN 索引) |
| 地理信息 | 需要扩展 | PostGIS(业界标准) |
| 数组类型 | 不支持 | 原生支持 |
| 自定义类型 | 不支持 | 支持 |
| 物化视图 | 不支持 | 支持 |
| CTE(WITH 语句) | 8.0+ 支持 | 一直支持 |
| 窗口函数 | 8.0+ 支持 | 一直支持 |
| 表继承 | 不支持 | 支持 |
| 外部数据包装器 | 不支持 | FDW(可查询外部数据源) |
8.3 SQL 标准兼容性
PostgreSQL 对 SQL 标准的支持更完整:
sql
-- PostgreSQL 支持的高级特性
-- 1. 数组操作
SELECT ARRAY[1, 2, 3] || ARRAY[4, 5]; -- {1,2,3,4,5}
-- 2. JSONB 操作
SELECT '{"name": "test"}'::jsonb -> 'name'; -- "test"
SELECT '{"name": "test"}'::jsonb ->> 'name'; -- test(文本)
-- 3. 范围类型
SELECT '[2025-01-01, 2025-12-31]'::daterange @> '2025-06-15'::date; -- true
-- 4. 递归 CTE
WITH RECURSIVE subordinates AS (
SELECT id, name, manager_id FROM employees WHERE id = 1
UNION ALL
SELECT e.id, e.name, e.manager_id
FROM employees e
JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates;
-- 5. 窗口函数
SELECT name, salary,
RANK() OVER (ORDER BY salary DESC) as rank,
SUM(salary) OVER () as total
FROM employees;
8.4 性能对比
读性能:
| 场景 | MySQL | PostgreSQL |
|---|---|---|
| 简单主键查询 | 快(聚簇索引) | 稍慢(需要回表) |
| 复杂查询 | 一般 | 更好(优化器更强) |
| 全文搜索 | 弱 | 强 |
写性能:
| 场景 | MySQL | PostgreSQL |
|---|---|---|
| 单行更新 | 快(原地更新) | 稍慢(插入新行) |
| 批量插入 | 快 | 快 |
| 高并发写入 | 好 | 好(B-Link Tree 优势) |
总结:
- 简单 CRUD:MySQL 略快
- 复杂查询:PostgreSQL 更强
- 特殊数据类型:PostgreSQL 完胜
8.5 运维对比
| 方面 | MySQL | PostgreSQL |
|---|---|---|
| 学习曲线 | 平缓 | 稍陡 |
| 社区资源 | 非常丰富 | 丰富 |
| 云服务支持 | 所有云厂商 | 所有云厂商 |
| 主从复制 | 成熟 | 成熟 |
| 高可用方案 | MHA、MGR、Orchestrator | Patroni、repmgr |
| 需要关注的问题 | 主从延迟 | VACUUM、表膨胀 |
8.6 如何选择
选 MySQL 的场景:
- 团队熟悉 MySQL
- 简单的 CRUD 业务
- 对运维复杂度敏感
- 需要大量社区资源和教程
选 PostgreSQL 的场景:
- 需要复杂查询和分析
- 需要 JSON 文档存储
- 需要地理信息处理
- 需要全文搜索
- 需要时序数据存储
- 追求 SQL 标准兼容
- 需要高度可扩展性
一句话总结:
- MySQL:简单、够用、生态好
- PostgreSQL:强大、全能、天花板
九、总结
9.1 核心架构回顾
| 组件 | 说明 |
|---|---|
| Postmaster | 主进程,管理连接和子进程 |
| Backend Process | 后端进程,处理客户端请求 |
| Shared Buffer | 共享缓冲区,缓存数据页 |
| WAL Buffer | WAL 缓冲区,缓存日志 |
| Background Workers | 后台进程,VACUUM、Checkpoint 等 |
9.2 索引能力总结
| 索引 | 能力 | 可替代 |
|---|---|---|
| B-Tree | 等值、范围查询 | MySQL |
| GIN | 全文搜索、JSONB | Elasticsearch、MongoDB |
| GiST | 地理位置、多维数据 | PostGIS |
| BRIN | 时序数据 | InfluxDB |
9.3 与 MySQL 的核心差异
| 差异点 | MySQL | PostgreSQL |
|---|---|---|
| 进程模型 | 多线程 | 多进程 |
| MVCC | Undo Log | 多版本元组 |
| 索引类型 | 主要是 B+Tree | 多种索引 |
| 扩展性 | 存储引擎可插拔 | Access Methods 可扩展 |
| 功能丰富度 | 够用 | 天花板 |
最后一句话:PostgreSQL 是数据库领域的"全干工程师",一个数据库顶多个中间件。如果你的业务需求复杂多变,PG 绝对是值得投资学习的选择。
热门专栏推荐
- Agent小册
- Java基础合集
- Python基础合集
- Go基础合集
- 大数据合集
- 前端小册
- 数据库合集
- Redis 合集
- Spring 全家桶
- 微服务全家桶
- 数据结构与算法合集
- 设计模式小册
- 消息队列合集
等等等还有许多优秀的合集在主页等着大家的光顾,感谢大家的支持
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😊
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🙏
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🌟