PostgreSQL 18 从新手到大师:实战指南 - 3.4 并行查询优化
一、并行查询概述
并行查询是PostgreSQL的一项重要特性,它允许将一个查询分解为多个子任务,由多个CPU核心并行执行,从而提高查询速度。
1.1 并行查询的基本概念
- 并行度(Degree of Parallelism):执行查询的并行工作进程数量
- 领导者进程(Leader Process):负责协调并行工作进程的进程
- 工作进程(Worker Process):实际执行查询子任务的进程
- Gather节点:在查询计划中负责收集和合并并行工作进程结果的节点
- Gather Merge节点:在查询计划中负责收集和合并有序结果的节点
1.2 并行查询的优势
- 提高查询速度:利用多个CPU核心并行执行查询
- 充分利用硬件资源:提高CPU利用率
- 减少响应时间:特别是对于大型表和复杂查询
- 提高系统吞吐量:允许同时处理更多查询
1.3 并行查询的适用场景
并行查询适用于以下场景:
- 大型表扫描:对大型表进行全表扫描或范围扫描
- 复杂聚合查询:包含SUM、COUNT、AVG等聚合函数的查询
- 连接查询:多个大型表的连接操作
- 排序操作:对大量数据进行排序
- 复杂计算:包含复杂表达式或函数的查询
二、并行查询的工作原理
2.1 并行查询的基本流程
- 查询优化器决策:查询优化器决定是否使用并行查询
- 并行计划生成:生成并行查询计划
- 并行工作进程创建:领导者进程创建并行工作进程
- 数据分片:将数据划分为多个片段,分配给不同的工作进程
- 并行执行:工作进程并行执行子任务
- 结果合并:领导者进程收集并合并工作进程的结果
- 结果返回:将最终结果返回给客户端
2.2 并行查询的执行模式
PostgreSQL支持以下几种并行查询执行模式:
-
并行扫描:
- 并行顺序扫描(Parallel Seq Scan)
- 并行索引扫描(Parallel Index Scan)
- 并行位图扫描(Parallel Bitmap Heap Scan)
-
并行连接:
- 并行嵌套循环连接(Parallel Nested Loop Join)
- 并行哈希连接(Parallel Hash Join)
- 并行合并连接(Parallel Merge Join)
-
并行聚合:
- 部分聚合(Partial Aggregation)
- 最终聚合(Final Aggregation)
-
并行排序:
- 并行排序(Parallel Sort)
- 并行合并(Parallel Merge)
2.3 并行查询的限制
并行查询有一些限制,以下情况不支持并行查询:
- 游标查询:使用游标执行的查询
- CTE查询:包含公共表表达式的查询(PostgreSQL 18之前)
- 递归查询:递归CTE查询(PostgreSQL 18之前)
- FOR UPDATE/SHARE查询:包含FOR UPDATE或FOR SHARE子句的查询
- 临时表查询:查询临时表
- 外部表查询:查询外部表
- 某些内置函数:如current_date、current_time等不稳定函数
三、并行查询的配置参数
PostgreSQL提供了多个参数来控制并行查询的行为。
3.1 主要配置参数
| 参数名 | 描述 | 默认值 | 建议值 |
|---|---|---|---|
max_parallel_workers_per_gather |
每个Gather节点的最大并行工作进程数 | 8 | 根据CPU核心数调整 |
max_parallel_workers |
系统范围内的最大并行工作进程数 | 8 | 通常为CPU核心数 |
max_worker_processes |
系统范围内的最大后台工作进程数 | 8 | 大于等于max_parallel_workers |
parallel_leader_participation |
领导者进程是否参与查询执行 | on | on |
min_parallel_table_scan_size |
表扫描使用并行查询的最小表大小 | 8MB | 根据表大小调整 |
min_parallel_index_scan_size |
索引扫描使用并行查询的最小索引大小 | 512kB | 根据索引大小调整 |
force_parallel_mode |
强制使用并行查询的模式 | off | off |
enable_parallel_append |
启用并行追加 | on | on |
enable_parallel_hash |
启用并行哈希连接 | on | on |
3.2 参数配置示例
-- 调整并行查询参数
ALTER SYSTEM SET max_parallel_workers_per_gather = 4;
ALTER SYSTEM SET max_parallel_workers = 8;
ALTER SYSTEM SET max_worker_processes = 16;
ALTER SYSTEM SET min_parallel_table_scan_size = '16MB';
-- 重启PostgreSQL使配置生效
-- sudo systemctl restart postgresql-18
四、并行查询计划分析
4.1 查看并行查询计划
使用EXPLAIN ANALYZE命令可以查看并行查询计划:
-- 启用并行查询
SET max_parallel_workers_per_gather = 4;
-- 查看并行查询计划
EXPLAIN ANALYZE
SELECT department, SUM(salary)
FROM employees
GROUP BY department;
4.2 并行查询计划示例
Finalize GroupAggregate (cost=1000.55..1000.67 rows=2 width=12) (actual time=0.123..0.125 rows=2 loops=1)
Group Key: department
-> Gather Merge (cost=1000.55..1000.65 rows=4 width=12) (actual time=0.120..0.122 rows=4 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Partial GroupAggregate (cost=0.55..0.63 rows=2 width=12) (actual time=0.050..0.051 rows=2 loops=2)
Group Key: department
-> Parallel Seq Scan on employees (cost=0.00..0.50 rows=50 width=10) (actual time=0.015..0.020 rows=50 loops=2)
Planning Time: 0.156 ms
Execution Time: 0.182 ms
4.3 并行查询计划中的关键节点
- Gather/Gather Merge:收集和合并工作进程的结果
- Partial Aggregate:部分聚合,在工作进程中执行
- Finalize Aggregate:最终聚合,在领导者进程中执行
- Parallel Seq Scan:并行顺序扫描
- Parallel Index Scan:并行索引扫描
- Parallel Hash Join:并行哈希连接
4.4 并行查询计划的解读
- Workers Planned:计划使用的并行工作进程数
- Workers Launched:实际启动的并行工作进程数
- Partial:表示在工作进程中执行的操作
- Finalize:表示在领导者进程中执行的最终操作
- Gather:表示收集工作进程结果的操作
五、PostgreSQL vs SQL Server 2019+ vs MySQL 8.0+:并行查询优化对比
在本节中,我们将PostgreSQL 18的并行查询优化与SQL Server 2019+和MySQL 8.0+的类似功能进行对比,分析它们在并行查询实现、配置和性能方面的差异。
5.1 并行查询支持对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 并行查询类型 | 并行SELECT/UPDATE/DELETE/MERGE/递归查询/CTE | 并行SELECT/INSERT/UPDATE/DELETE/MERGE | 并行SELECT(有限支持) |
| 并行扫描 | 支持并行顺序扫描、索引扫描、位图扫描 | 支持多种扫描类型的并行执行 | 支持并行全表扫描和索引扫描 |
| 并行连接 | 支持并行嵌套循环、哈希连接、合并连接 | 支持多种连接类型的并行执行 | 支持有限的并行连接 |
| 并行聚合 | 支持部分聚合和最终聚合 | 支持并行聚合 | 支持有限的并行聚合 |
| 并行排序 | 支持并行排序和合并 | 支持并行排序 | 无原生支持 |
| 并行分区操作 | 支持并行分区扫描和维护 | 支持并行分区操作 | 支持有限的并行分区操作 |
5.2 并行查询配置对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 并行度控制 | 动态并行度调整,支持领导者进程参与 | 自适应并行度,支持MAXDOP配置 | 基于成本的并行度,最高8个线程 |
| 并行度配置参数 | max_parallel_workers_per_gather, max_parallel_workers | MAXDOP, Cost Threshold for Parallelism | max_parallel_workers_per_gather |
| 并行触发阈值 | 基于表大小和索引大小 | 基于查询成本 | 基于表大小和查询成本 |
| 领导者进程参与 | 支持,可配置parallel_leader_participation | 支持,领导者进程参与执行 | 不支持 |
| 并行查询开关 | 多个参数控制不同类型的并行操作 | 全局和查询级别的开关 | 有限的开关控制 |
5.3 并行查询性能对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 性能提升 | 显著,特别是对于大型表和复杂查询 | 显著,企业级性能优化 | 有限,主要适合简单查询 |
| 资源利用率 | 良好,能够充分利用CPU核心 | 优秀,精细的资源管理 | 一般,资源利用效率不高 |
| 并行度自适应 | 支持动态并行度调整 | 支持自适应并行查询 | 有限的自适应能力 |
| 查询计划优化 | 改进的并行计划选择 | 成熟的并行计划优化 | 简单的并行计划生成 |
| 大规模数据处理 | 优秀,适合TB级数据 | 优秀,适合PB级数据 | 良好,适合GB级数据 |
5.4 并行查询限制对比
| 特性 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 游标查询 | 不支持并行 | 支持并行游标 | 不支持并行 |
| CTE查询 | PostgreSQL 18支持并行CTE | 支持并行CTE | 不支持并行CTE |
| 递归查询 | PostgreSQL 18支持并行递归查询 | 支持并行递归查询 | 不支持并行递归查询 |
| 临时表查询 | 不支持并行 | 支持并行临时表查询 | 不支持并行 |
| 外部表查询 | 不支持并行 | 支持并行外部表查询 | 不支持并行 |
| 不稳定函数 | 不支持包含不稳定函数的查询 | 支持,有相应的处理机制 | 不支持 |
5.5 并行查询适用场景对比
| 场景 | PostgreSQL 18 | SQL Server 2019+ | MySQL 8.0+ |
|---|---|---|---|
| 大型表扫描 | 非常适合 | 非常适合 | 适合 |
| 复杂聚合查询 | 非常适合 | 非常适合 | 适合 |
| 多表连接查询 | 适合 | 非常适合 | 有限支持 |
| 排序操作 | 适合 | 非常适合 | 不支持 |
| 复杂计算 | 适合 | 非常适合 | 有限支持 |
| OLAP查询 | 适合 | 非常适合 | 有限支持 |
| OLTP查询 | 适合简单OLTP查询 | 支持混合工作负载 | 适合高并发OLTP |
六、并行查询的优化技巧
6.1 调整并行度
根据系统的CPU核心数和查询复杂度调整并行度:
-- 为复杂查询设置较高的并行度
SET max_parallel_workers_per_gather = 8;
-- 为简单查询设置较低的并行度或禁用并行
SET max_parallel_workers_per_gather = 1;
-- 或禁用并行
SET max_parallel_workers_per_gather = 0;
6.2 优化表设计
-
合理设置表的存储参数:
-- 设置合适的填充因子 ALTER TABLE employees SET (fillfactor = 80); -
使用合适的索引:
- 对于经常进行范围查询的列,创建B-tree索引
- 对于经常进行聚合查询的列,考虑创建部分索引
-
分区表优化:
- 对大型表进行分区
- 启用并行分区扫描
-- 启用并行分区扫描 SET enable_parallel_partition_scan = on;
6.3 优化查询语句
-
避免不必要的列:只查询需要的列
-- 好的做法:只查询需要的列 SELECT id, name FROM employees; -- 不好的做法:查询所有列 SELECT * FROM employees; -
优化聚合查询:
- 使用合适的聚合函数
- 考虑使用部分聚合
-- 优化聚合查询 SELECT department, SUM(salary) FROM employees GROUP BY department; -
优化连接查询:
- 选择合适的连接顺序
- 使用合适的连接类型
-- 优化连接查询 SELECT e.name, d.department_name FROM employees e JOIN departments d ON e.department_id = d.id; -
避免复杂表达式:
- 将复杂表达式移到WHERE子句中
- 考虑使用生成列
-- 使用生成列 ALTER TABLE employees ADD COLUMN full_name GENERATED ALWAYS AS (first_name || ' ' || last_name) STORED;
6.4 优化系统资源
-
调整内存配置:
-- 增加共享缓冲区 ALTER SYSTEM SET shared_buffers = '4GB'; -- 增加工作内存 ALTER SYSTEM SET work_mem = '64MB'; -- 增加维护工作内存 ALTER SYSTEM SET maintenance_work_mem = '1GB'; -
调整存储配置:
- 使用高性能存储设备(如SSD)
- 调整RAID级别
- 优化文件系统参数
-
调整CPU配置:
- 启用CPU超线程
- 调整CPU频率
- 考虑使用NUMA架构
七、并行查询的监控
7.1 查看并行查询状态
-- 查看当前并行查询
SELECT
pid,
query,
state,
backend_type,
query_start
FROM
pg_stat_activity
WHERE
backend_type LIKE '%Parallel%' OR
query LIKE '%Parallel%';
-- 查看并行工作进程状态
SELECT
pid,
backend_type,
query
FROM
pg_stat_activity
WHERE
backend_type = 'parallel worker';
7.2 查看并行查询统计信息
-- 查看并行查询统计信息
SELECT * FROM pg_stat_progress_parallel;
-- 查看系统级并行查询统计
SELECT
name,
setting,
unit,
short_desc
FROM
pg_settings
WHERE
name LIKE '%parallel%';
7.3 监控并行查询性能
使用EXPLAIN ANALYZE监控并行查询性能:
-- 监控并行查询性能
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT department, SUM(salary)
FROM employees
GROUP BY department;
7.4 识别并行查询瓶颈
-
CPU瓶颈:
- 监控CPU使用率
- 查看是否有工作进程CPU使用率达到100%
-
I/O瓶颈:
- 监控磁盘I/O使用率
- 查看是否有大量的磁盘读取
-
内存瓶颈:
- 监控内存使用率
- 查看是否有内存不足的情况
-
网络瓶颈:
- 监控网络流量
- 查看是否有大量的数据传输
八、并行查询的最佳实践
8.1 配置最佳实践
-
根据CPU核心数调整并行度:
- 对于N核CPU,max_parallel_workers_per_gather建议设置为N/2到N-1
- max_parallel_workers建议设置为N
-
合理设置并行查询的触发阈值:
- 根据表大小调整min_parallel_table_scan_size
- 根据索引大小调整min_parallel_index_scan_size
-
启用并行leader参与:
- 设置parallel_leader_participation = on
- 充分利用领导者进程的CPU资源
-
启用并行哈希连接:
- 设置enable_parallel_hash = on
- 提高连接查询的并行性能
8.2 查询优化最佳实践
-
为大型表启用并行查询:
-- 为特定表启用并行查询 ALTER TABLE large_table SET (parallel_workers = 4); -
避免过度并行:
- 对于简单查询,禁用并行或使用较低的并行度
- 避免同时执行过多的并行查询
-
优化聚合查询:
- 使用GROUP BY时,确保分组列上有索引
- 考虑使用部分聚合
-
优化连接查询:
- 确保连接列上有索引
- 选择合适的连接顺序
- 使用合适的连接类型
8.3 监控和维护最佳实践
-
定期监控并行查询性能:
- 使用EXPLAIN ANALYZE定期分析查询性能
- 监控系统资源使用情况
-
定期更新统计信息:
-- 更新统计信息 ANALYZE employees; -
定期重建索引:
-- 重建索引 REINDEX TABLE employees; -
测试并行查询的效果:
- 比较并行查询和串行查询的性能差异
- 调整参数,找到最佳配置
8.4 故障排除最佳实践
-
并行查询不启动:
- 检查是否满足并行查询的条件
- 检查并行查询参数设置
- 查看查询计划,确认是否选择了并行计划
-
并行查询性能不佳:
- 检查是否存在资源瓶颈
- 检查并行度是否合适
- 优化查询语句
-
并行查询导致系统负载过高:
- 降低并行度
- 限制并行查询的数量
- 调整系统资源配置
九、实践项目:并行查询性能优化
9.1 项目目标
- 配置PostgreSQL并行查询
- 测试并行查询的性能
- 优化并行查询配置
- 监控并行查询状态
- 识别和解决并行查询瓶颈
9.2 项目步骤
-
环境准备:
- 安装PostgreSQL 18
- 配置必要的参数
- 创建测试数据库和表
- 插入大量测试数据
-
并行查询配置:
- 调整并行查询相关参数
- 启用并行查询
- 配置表的并行工作进程数
-
性能测试:
- 执行各种类型的查询,包括全表扫描、聚合查询、连接查询等
- 使用EXPLAIN ANALYZE分析查询性能
- 比较并行查询和串行查询的性能差异
-
并行查询优化:
- 调整并行度
- 优化表设计
- 优化查询语句
- 调整系统资源配置
-
监控并行查询:
- 监控并行查询的状态和性能
- 识别并行查询瓶颈
- 解决并行查询中的问题
9.3 项目验证
- 并行查询性能比串行查询提高至少50%
- 系统资源利用率合理
- 能够识别和解决并行查询瓶颈
- 并行查询配置优化合理
十、并行查询的未来发展
10.1 PostgreSQL 18的并行查询改进
PostgreSQL 18在并行查询方面进行了多项改进:
-
支持更多类型的并行查询:
- 并行UPDATE/DELETE
- 并行MERGE
- 并行递归查询
- 并行CTE
-
优化的并行执行机制:
- 动态并行度调整
- 更好的负载均衡
- 减少同步开销
-
改进的并行查询计划:
- 更准确的并行度估计
- 更好的并行计划选择
10.2 并行查询的发展趋势
- 更智能的并行度调整:根据系统负载和查询复杂度自动调整并行度
- 更广泛的并行查询支持:支持更多类型的查询和操作
- 更好的资源管理:更细粒度的资源控制和隔离
- 与分布式系统的集成:支持分布式并行查询
- 更好的监控和诊断工具:提供更详细的并行查询监控信息
十一、总结
并行查询是PostgreSQL提高查询性能的重要特性,通过利用多个CPU核心并行执行查询,可以显著提高查询速度和系统吞吐量。
通过本章的学习,你应该已经掌握了:
- 并行查询的基本概念和工作原理
- 并行查询的配置参数和优化技巧
- 并行查询计划的分析和解读
- 并行查询的监控和维护
- 并行查询的最佳实践和故障排除
在实际应用中,合理配置和优化并行查询,可以充分利用系统的硬件资源,提高查询性能,满足高并发、大数据量的查询需求。
十二、思考与练习
- 什么是并行查询?并行查询有哪些优势?
- 并行查询的基本工作原理是什么?
- PostgreSQL支持哪些类型的并行查询?
- 如何配置PostgreSQL的并行查询?
- 如何分析并行查询计划?
- 如何优化并行查询的性能?
- 如何监控并行查询的状态和性能?
- 并行查询的最佳实践有哪些?
- 如何识别和解决并行查询瓶颈?
- PostgreSQL 18在并行查询方面有哪些改进?
更多推荐



所有评论(0)