暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

POSTGRESQL如何估计并行查询

飞象数据 2019-11-08
755

并行查询最早是在PostgreSQL 9.6中引入的,此功能自那时以来已得到扩展。在PostgreSQL 11和PostgreSQL 12中,数据库引擎添加了更多功能。但是,仍有一些并行查询的问题经常出现,这绝对值得一些澄清。

估计顺序扫描的成本

为了向您展示该过程的工作原理,我创建了一个仅包含两列的简单表:

test=# CREATE TABLE t_test AS  SELECT id AS many, id % 2 AS few  FROM generate_series(1, 10000000) AS id;SELECT 10000000 test=# ANALYZE;ANALYZE

“many”列包含1000万个不同的条目。“few”列将包含两个不同的值。但是,出于这个示例的考虑,所有合理的大表都可以使用。

我们来看看PostgreSQL优化器是如何工作的:

test=# SET max_parallel_workers_per_gather TO 0;SETtest=# explain SELECT count(*) FROM t_test;                                 QUERY PLAN------------------------------------------------------------------------ Aggregate (cost=169248.60..169248.61 rows=1 width=8)   -> Seq Scan on t_test (cost=0.00..144248.48 rows=10000048 width=0) (2 rows)

默认配置将自动使PostgreSQL进行并行顺序扫描。我们希望阻止它这样做以使内容更易于理解。

可以通过将max_parallel_workers_per_gather变量设置为0来关闭并行查询。如在执行计划中所看到的,顺序扫描的成本估计为144248。总查询成本预计为169248。但是PostgreSQL如何得出这个数字?让我们看一下以下清单:

test=# SELECT pg_relation_size('t_test') AS size,              pg_relation_size('t_test')  8192 AS blocks;  size     | blocks-----------+-------- 362479616 | 44248(1 row)

t_test表约为350 MB,由44248个块组成。每个块必须顺序读取和处理。必须对那些块中的所有行进行计数才能得出最终结果。优化器将使用以下公式估算成本:

test=# SELECT current_setting('seq_page_cost')::numeric * 44248            + current_setting('cpu_tuple_cost')::numeric * 10000000            + current_setting('cpu_operator_cost')::numeric * 10000000;   ?column?------------- 169248.0000(1 row)

正如你所看到的,几个参数,这里正在使用:seq_page_cost告诉优化的阅读顺序块的成本。最重要的是,我们必须考虑到所有这些行都必须经过CPU(cpu_tuple_cost)才能最终计数。使用cpu_operator_cost是因为计数基本上与为每一行调用“ +1”相同。因此,顺序扫描的总成本为169248,这正是我们在计划中看到的。

估计并行顺序扫描

PostgreSQL的估计顺序扫描的方式往往有点模糊。因此,让我们看一下执行计划,看看会发生什么:

test=# SET max_parallel_workers_per_gather TO default;SETtest=# explain SELECT count(*) FROM t_test;                                  QUERY PLAN------------------------------------------------------------------------------------ Finalize Aggregate (cost=97331.80..97331.81 rows=1 width=8) -> Gather (cost=97331.58..97331.79 rows=2 width=8)    Workers Planned: 2    -> Partial Aggregate (cost=96331.58..96331.59 rows=1 width=8)       -> Parallel Seq Scan on t_test (cost=0.00..85914.87 rows=4166687 width=0)(5 rows)

如您所见,PostgreSQL决定使用两颗CPU。但是PostgreSQL  是如何提出这一部分的呢?“行= 4166687”

答案在于以下公式:

10000048.0 (2 + (1 – 0.3 * 2)) = 4166686.66 rows

10000048行是PostgreSQL期望在表中的行数( 由ANALYZE之前确定)。接下来的事情是,PostgreSQL尝试去 确定有多少工作都必须由一个核心来完成。但是,公式 实际上是什么意思?

estimate = estimated_rows / (number_of_cores + (1 – leader_contribution * number_of_cores)

leader进程通常花费大量精力来计算结果。但是,我们假设leader将约30%的时间用于服务工作进程。因此,随着 核心数量的增加,leader的贡献将下降。如果有4个或更多的内核在工作,则leader将不再对扫描做出有意义的贡献-因此PostgreSQL将仅根据内核数来计算表的大小,而不是使用刚刚显示的公式。

其他并行操作

其他并行操作将使用类似的除数来估计。位图扫描等也是相同工作方式。


本文翻译自:https://www.cybertec-postgresql.com/en/how-postgresql-estimates-parallel-queries/


文章转载自飞象数据,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论