1. PostgreSQL 查询处理全景图
PostgreSQL 作为企业级开源数据库,其 SQL 执行引擎采用经典的火山模型(Volcano Model),但在此基础上进行了诸多优化创新。整个执行流程可以划分为五个关键阶段:
- 语法解析层:将 SQL 文本转换为解析树(Parse Tree)
- 语义分析层:生成查询树(Query Tree)
- 查询重写层:应用规则系统转换查询树
- 计划生成层:产出最优执行计划(Plan Tree)
- 执行引擎层:通过执行器(Executor)处理元组流
这种分层架构使得每个阶段可以独立优化,例如在 PostgreSQL 14 中引入的预处理语句性能优化就主要作用于语法解析层。
2. 语法解析深度解析
2.1 词法分析与语法分析
PostgreSQL 使用 Flex/Bison 组合实现词法语法分析:
sql复制SELECT * FROM users WHERE id = 1;
经过词法分析后生成 token 序列:
code复制SELECT(KEYWORD), *(OPERATOR), FROM(KEYWORD),
users(IDENTIFIER), WHERE(KEYWORD),
id(IDENTIFIER), =(OPERATOR), 1(CONST_INT)
语法分析阶段会根据 gram.y 中定义的 500+ 条语法规则构建解析树。以 WHERE 子句为例,其语法规则定义为:
bison复制where_clause:
WHERE a_expr { $$ = $2; }
| /* EMPTY */ { $$ = NULL; }
;
2.2 解析树内存结构
解析树节点使用 Node 结构体表示,所有语法单元都继承自该结构。关键节点类型包括:
- SelectStmt:SELECT 语句主体
- ColumnRef:列引用
- A_Expr:条件表达式
- RangeVar:表引用
内存中的解析树示例:
c复制typedef struct SelectStmt {
NodeTag type;
List *targetList; /* 目标列 */
List *fromClause; /* FROM 子句 */
Node *whereClause; /* WHERE 条件 */
...
} SelectStmt;
提示:通过设置 debug_print_parse 参数可以输出解析树结构,这对复杂查询调试非常有帮助。
3. 语义分析与查询树生成
3.1 名称解析过程
语义分析阶段需要解决:
- 表名到 OID 的映射(搜索 search_path)
- 列名到表属性的绑定
- 函数名重载决议
- 隐式类型转换检查
以 SELECT name FROM users 为例:
- 在 pg_class 中查找 users 表的 OID
- 验证当前用户是否有该表的 SELECT 权限
- 在 pg_attribute 中查找 name 列的属性号(attnum)
3.2 查询树结构优化
生成的查询树采用 Query 结构体表示,相比解析树:
- 所有名称替换为 OID 引用
- 添加了权限检查标记
- 规范化了表达式结构
- 展开了视图定义
关键优化包括:
- 常量表达式预计算
- 布尔表达式规范化
- 子链接提升(SubLink to SubPlan)
4. 查询重写与规则系统
4.1 重写规则处理流程
PostgreSQL 的重写系统按照以下顺序应用规则:
- 视图展开(VIEW rules)
- 行级安全策略(RLS policies)
- 自定义重写规则(CREATE RULE)
例如对于视图:
sql复制CREATE VIEW active_users AS
SELECT * FROM users WHERE is_active = true;
查询 SELECT * FROM active_users 会被重写为:
sql复制SELECT * FROM users WHERE is_active = true;
4.2 规则系统实现机制
重写规则存储在 pg_rewrite 系统表中,其执行过程:
- 匹配查询树与规则条件
- 对匹配的规则生成替代查询树
- 递归处理新生成的查询树
特殊规则类型:
- INSTEAD 规则:完全替换原操作
- ALSO 规则:在原操作基础上追加
5. 查询计划生成原理
5.1 基于成本的优化器
PostgreSQL 优化器采用自底向上的动态规划算法,核心步骤:
-
基表访问路径生成:
- 顺序扫描(seqscan)
- 索引扫描(indexscan)
- 位图扫描(bitmapscan)
通过 cost_seqscan() 等函数计算各路径成本
-
连接路径探索:
- 嵌套循环(nested loop)
- 哈希连接(hash join)
- 归并连接(merge join)
使用 geqo_threshold 控制遗传算法使用
-
最优路径选择:
python复制def choose_best_path(paths): min_cost = float('inf') best_path = None for path in paths: if path.total_cost < min_cost: min_cost = path.total_cost best_path = path return best_path
5.2 计划树关键结构
执行计划由 PlannedStmt 表示,主要包含:
- Plan 树:执行操作节点
- 参数列表:运行时参数
- 结果关系:输出目标
计划节点公共字段:
c复制typedef struct Plan {
NodeTag type;
double startup_cost; /* 初始成本 */
double total_cost; /* 总成本 */
int plan_rows; /* 预估行数 */
List *targetlist; /* 目标列 */
...
} Plan;
6. 执行引擎工作机制
6.1 火山模型实现
PostgreSQL 执行器采用经典的迭代器模型:
c复制TupleTableSlot *
ExecProcNode(PlanState *node)
{
if (node->chgParam != NULL)
ExecReScan(node);
return node->ExecProcNode(node);
}
主要节点类型处理逻辑:
- 扫描节点(Scan):从存储层获取元组
- 连接节点(Join):组合多表数据
- 聚合节点(Agg):执行分组计算
- 排序节点(Sort):内存/磁盘排序
6.2 并行查询执行
PostgreSQL 的并行执行框架包含:
- 领导者进程(leader):协调并行workers
- 工作者进程(worker):执行子计划
- 共享内存区:用于进程间通信
并行执行关键参数:
- max_parallel_workers_per_gather
- min_parallel_table_scan_size
- parallel_setup_cost
7. 执行过程监控与优化
7.1 执行统计视图
通过 pg_stat_statements 可获取:
sql复制SELECT query, calls, total_time, rows
FROM pg_stat_statements
ORDER BY total_time DESC LIMIT 5;
关键性能指标:
- 缓冲区命中率(hit ratio)
- 临时文件使用量(temp files)
- WAL 生成量(wal size)
7.2 执行计划分析技巧
使用 EXPLAIN ANALYZE 进行性能诊断:
code复制EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM large_table WHERE id = 100;
常见性能问题模式:
- 预估行数与实际差异大 → 统计信息不准
- 嵌套循环连接效率低 → 缺少连接条件索引
- 排序占用内存过大 → work_mem 不足
8. 高级执行特性
8.1 JIT 编译执行
PostgreSQL 11+ 支持 LLVM 即时编译:
- 将表达式编译为机器码
- 加速条件判断和计算
- 通过 jit_above_cost 控制触发阈值
启用方式:
sql复制SET jit = on;
SET jit_provider = 'llvmjit';
8.2 增量物化技术
PostgreSQL 14 引入的优化:
- 延迟物化(Lazy Materialization)
- 增量排序(Incremental Sort)
- 窗口函数优化(WindowAgg)
示例:
sql复制/* 传统执行方式 */
SELECT * FROM (SELECT * FROM big_table ORDER BY id) t LIMIT 10;
/* 增量排序优化 */
SELECT * FROM big_table ORDER BY id LIMIT 10;
9. 执行过程问题排查
9.1 常见错误处理
-
内存不足:
- 症状:无法创建临时文件
- 解决:调整 work_mem/maintenance_work_mem
-
锁冲突:
- 症状:查询长时间挂起
- 诊断:SELECT * FROM pg_locks;
-
统计信息过时:
- 症状:执行计划突然变差
- 解决:ANALYZE 更新统计信息
9.2 性能调优检查表
| 问题类型 | 检查项 | 调优方法 |
|---|---|---|
| 慢查询 | 执行计划异常 | 创建缺失索引 |
| 高CPU | 低效连接操作 | 优化连接策略 |
| 内存溢出 | work_mem 设置 | 调整内存参数 |
| IO瓶颈 | 缓冲区命中率低 | 增加 shared_buffers |
10. 执行引擎最新发展
PostgreSQL 16 中的执行优化:
- 增强型并行聚合(Parallel Aggregate)
- 异步预取(Asynchronous Prefetch)
- 向量化执行(实验性)
- 存储过程内联(Procedure Inlining)
性能对比测试显示:
- 分析型查询速度提升 2-5 倍
- 事务处理吞吐量提高 30%
- 内存使用效率提升 40%