Author: 义从
大家都知道,PostgreSQL 近几大版本中加入了很多 OLAP 相关特性。9.6 的并行扫描应该算最大的相关特性。在今年发布的 10.0 中,并行扫描也在不断加强,新增了并行的索引扫描。
我们知道并行扫描是支持外部数据源的。在云上,有很多存储存储产品可以以外部数据源的形式做数据库的外部存储。例如,阿里云的 OSS 和 AWS 的 S3 都是绝佳的外部数据源。云上的 PostgreSQL 和他们的结合可以给用户提供既廉价又高性能数存储的方案。
另人欣喜的是,PostgreSQL 的外部表对外提供了可编程接口,并且支持并行扫描框架。利用它可以使 PostgreSQL 的外部数据源访问效率得到质的提升。
并行查询是 PostgreSQL 引入的一个大特性,它可以优化 SQL 语句的执行方式,从传统的单一进程,最多使用单个 CPU 运算的模式,提升到多进程,协同完成工作的模式。
并行查询消耗更多的硬件资源,大大提高了任务的执行效率。 在 PostgreSQL 中,一个 SQL 任务是否可以被并行化,可以通过查看 SQL 的执行计划(Plan)的方式看到。
例如:
EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%';
QUERY PLAN
-------------------------------------------------------------------------------------
Gather (cost=1000.00..217018.43 rows=1 width=97)
Workers Planned: 2
-> Parallel Seq Scan on pgbench_accounts (cost=0.00..216018.33 rows=1 width=97)
Filter: (filler ~~ '%x%'::text)
(4 rows)
可以看到,上面的 SQL 采用了并行的方式执行,它使用了2个额外的并行工作进程(共3个进程)完成工作。
合理的配置下列参数能让 PostgreSQL 成功开启并行查询特性。
外部表是 PostgreSQL 引入外部数据的入口,任何的外部数据源都可以使用该接口把数据引入到数据库中。用户可以像访问表一样读写外部数据源上的数据。 目前 PostgreSQL 支持的常见外部数据源有 MySQL Oracle PostgreSQL OSS S3 等。 PostgreSQL 在引入并行查询时也支持了外部表的并行查询,并扩展了之前的编程接口。
一条 SQL 语句的执行通常经历下面的过程:
1) 语法分析和语意分析 2) 查询优化 3) 查询执行
外部表的扫描在阶段 2 和 3 都有相应的操作
并行查询模式的引入,是 PostgreSQL 在传统的 Pipeline 模式上的较大改动。
大致的改进点如下,这部分也是外部表的并行查询模式实现所要注意的
一 查询优化阶段
提供给优化器并行模型的各类代价信息,参与优化器进行整体的代价评估。 当并行模式最终被确认为最优方案后,优化器会给出并行模式的执行计划。
二 查询执行器阶段
执行器得到一个带有并行执行节点的计划,还要进行如下工作
上诉工作中框架相关的通用工作 PostgreSQL 已经完成,我们需要在并行框架下实现各阶段的部分逻辑。下面将会重点说明这部分细节。
实现外部表的并行扫描需要注意上述环节中每个环节,下面描述概要设计
一: 查询优化阶段
实现 IsForeignScanParallelSafe ,返回 true。 标志该数据源可以并行化。
二: 查询执行阶段
并行任务关键当然是把一个大的任务拆分成多个尽可能不相关的子任务,让这些子任务被并行的完成。
例如:
1 对外部 MySQL 一张表 t 的读取,可以按照表 t 主键的值域把数据拆分成 N 部分,让并行 worker 分别读取其中一部分。
2 对外部数据源 oss 一个目录 dir1 中多个文件中数据的读取,可以把这批文件均匀的分成 N 份,让并行 worker 分别完成其中的一部分。
如何合理的切分子任务,往往决定了最终的并行效果。合理的切分数据会使并行任务间尽量少的交互,最终任务完成耗时和并行工作进程数线性相关。
执行器的具体工作:
实现 EstimateDSMForeignScan 计算需求的共享内存大小。这部分内存将用户存放整个并行任务的相关信息。 这部分流程主进程完成,即 Gather 节点完成。
实现 InitializeDSMForeignScan 分配共享内存,放入相关信息。 我们把整个大任务拆分成一个子任务队列,并存入到共享内存中,初始化锁等信息。 这部分流程也主进程完成,即 Gather 节点完成。
实现 InitializeWorkerForeignScan 并行 Worker 读取共享内存上的信息,获取子任务,准备正式开始工作。
数据的读写操作。 这部分的实现尽量兼容传统模式的数据读取,或小幅调整。
实现 ShutdownForeignScan 数据扫描完成的后清理工作。
详细的 Foreign Data Wrapper 接口实现说明在这
并行查询能大大提高数据的访问效率,他把外部数据源深度整合到 PostgreSQL 中。可以轻松的和本地数据一起做复杂的运算。同时,我们也能利用这套机制,实现高效的外部数据导入工作。