导图社区 greeplum 执行计划
GREENPLUM是一个关系型数据库集群. 它实际上是由数个独立的数据库服务组合成的逻辑数据库,本图整理了相关的知识点,希望对你有帮助。
编辑于2023-02-07 15:42:12执行计划相关
explain sql
自下向上分析
cost:
以磁盘页面获取为单位度量
1.0等于一次顺序磁盘页面读取
第一个估计是得到第一行的启动代价
第二个估计是得到所有行的总代价
rows
这个计划节点输出的总行数
这个数字通常小于被该计划节点处理或者扫描的行数
它反映了任意WHERE子句条件的估计选择度
理想情况下,最顶层节点的估计近似于该查询实际返回、更新或者删除的行数
width
这个计划节点输出的所有行的总字节数。这个长度值是根据pg_statistic表中的统计信息来计算的
一个节点的cost包括其子节点的cost
最顶层计划节点有对于该计划估计的总执行cost
explain analyze sql 实际执行后获取真实的成本。可以对比估计与真实的差异
关联方法
Hash Join (高效的join方式) 较小的表构建一个哈希表,用连接列作为哈希键。然后扫描较大的表,为连接列计算哈希键并且探索哈希表寻找具有相同哈希键的行。哈希连接通常是Greenplum数据库中最快的连接。解释计划中的Hash Cond标识要被连接的列
Merge Join 排序两个数据集并且将它们合并起来。归并连接对预排序好的数据很快,但是在现实世界中很少见。为了更偏爱Merge Join,可把系统配置参数enable_mergejoin设置为ON
NestLoop Join
数据扫描方法
Seq Scan:顺序扫描。有时候可能带有Dynamic前缀,表示分区顺序扫描
Index Scan:索引扫描
Bitmap Heap Scan:位图堆表扫描
Tid Scan:通过隐藏字段 ctid 扫描
Subquery Scan '*SELECT*':子查询扫描
Function Scan:函数扫描
Shared Scan:扫描shared_buffer中的某个slice
相关参数
enable_bitmapscan
enable_hashagg
enable_indexonlyscan
enable_material
enable_nestloop
enable_sort
enable_groupagg
enable_hashjoin
enable_indexscan
enable_mergejoin
enable_seqscan
enable_tidscan
其他操作符
Materialize – 优化器将一个子查询物化一次,这样就不用为顶层行重复该工作。
InitPlan – 一个预查询,被用在动态分区消除中,当执行时还不知道优化器需要用来标识要扫描分区的值时,会执行这个预查询。
Sort – 为另一个要求排序数据的操作(例如Aggregation或者Merge Join)准备排序数据。
Group By – 通过一个或者更多列分组行。
Group/Hash Aggregate – 使用哈希聚集行。
Append – 串接数据集,例如在整合从分区表中各分区扫描的行时会用到。
Filter – 使用来自于一个WHERE子句的条件选择行
Limit – 限制返回的行数。
基于成本的优化策略
统计信息
analyze 支持3种粒度
ANALYZE是一种采样统计算法,通常不会扫描表中所有的数据,但是对于大表,也仍会消耗一定的时间和计算资源。 采样统计会有精度的问题,因此Greenplum也提供了一个参数default_statistics_target,调整采样的比例。简单说来,这个值设置得越大,采样的数量就越多,准确性就越高,但是消耗的时间和资源也越多
ANALYZE; // 搜集当前库所有表的统计信息,需要有权限才行
ANALYZE foo; // 搜集foo表的统计信息
ANALYZE foo(bar); // 只搜集bar列的统计信息
ANALYZE会给目标表加SHARE UPDATE EXCLUSIVE锁,也就是与UPDATE,DELETE,还有DDL语句冲突。
表级别的信息(表的数据量及表大小)保存在 pg_class 中的 reltuples(行数) 和 relpages(Greenplum中一个page为32KB) 字段中,
reltuples和relpages不一定能对齐,比如条数看起来不多的表,实际占用的page数目很大,这种一般是由于数据膨胀(bloat)造成,这时候需要vacuum等操作。
字段级别的结果保存在系统表 pg_statistic 中
收集
自动
gp_autostats_mode
none
on_change【就是在数据变化量达到gp_autostats_on_change_threshold参数配置的量之后,系统就会自动收集统计信息】
on_no_stats【如果表还没有统计信息,这时候写入数据会导致自动收集,这之后,无论表数据变化多大,都只能手动收集了】
gp_autostats_on_change_threshold
手功
批量加载数据后,比如COPY
创建索引之后
INSERT, UPDATE, and DELETE大量数据之后
cost 模型
cpu_index_tuple_cost
cpu_operator_cost
cpu_tuple_cost
seq_page_cost
random_page_cost
gp_motion_cost_per_row【motion操作的开销,0 表示是cpu_tuple_cost的两倍】
effective_cache_size【设置有关Postgres查询优化器的单个查询可用的磁盘高速缓存(page cache)的有效大小的假设,估算使用指数的成本的因素; 较高的值使得更有可能使用索引扫描,较低的值使得更有可能使用顺序扫描 】
Motion
除了常见的数据库操作(例如表扫描,联接,聚合,排序等)之外,Greenplum数据库还有一种名为motion的算子。motion用于在segment之间移动元组。
每个 Motion 节点均有两个属性:sliceld 和 segments
sliceld 是这个 Slice 在并行查询计划里的唯一标识
segments 是参与执行该 Slice 的 Segment实例数量, 要么是 l,对应 Master 节点;要么是N, 对应整个 Greenplum 集群中 Segment 实例总数
Broadcast Motion (N:N):广播数据。每个节点向其他节点广播需要发送的数据。每个节点都会有一份全量数据
Redistribute Motion (N:N):重新分布数据。目的是将属于同一个关联键的数据都在同一个Segment上
重新分布数据,当需要做跨库关联或者聚合的时候,当数据不能满足广播的条件,或者广播的消耗过大时,Greenplum就会选择重分布数据,即数据按照新的分布键(关联键)重新打散到每个Segment上,重分布一般在以下三种情况发生
关联:将每个Segment的数据根据关联键重新计算hash值,并根据greenplum的路由算法路由到目标子节点中,使关联时属于同一个关联键的数据都在同一个Segment上。
Group By:当表需要Group By,但是Group By的字段不是分布键时,为了使Group By的字段在同一个segment中,Greenplum会分两个Group By操作来执行,首先,在单个segment上执行一个Group By操作,从而减少需要重分布的数据量;然后将结果数据按照Group By字段重分布,之后再做聚合获得最终结果。
开窗函数:跟Group By类似,开窗函数的实现也需要将数据重分布到每个节点上进行计算,不过其实比Group By更复杂一些
Gather Motion (N:1):聚合汇总数据。每个节点将 join 后的数据发到一个单节点上,通常是发到主节点 master 。
Slice
为了在查询执行期间实现最大的并行度,Greenplum将查询计划的工作划分为slices
slice是计划中可以独立进行处理的部分,其所对应的数据或者是本地数据,或者是通过计划树下层Motion节点传递过来的数据
每一个Motion节点都会生成一个Slice,每一个Slice由一个进程来执行对应此部分的查询计划
通过Slice将查询计划并行化,既可加快查询执行速度,又可以充分提高系统CPU等资源的利用率
Gang
所有 Segment 实例上执行同一 Sliceld 操作的一组进程称为一个 Gang。
在一个规模为N 的 Greenplum 集群中, Gang 的大小或者是N (N-Gang), 或是 1 (1-Gang)。
N-Gang 通常对 应运行在 Segment 实例上的普通操作。 例如,在N个 Segment 实例上,每个 Segment 启动一个进程执行全表扫描操作。
1-Gang 通常对应运行在 Master 节点上的 Gather Motion, 启动 一个进程收集所有 Segment 上的数据进行汇总。
Gang 的大小即为查询的并行度。