实验九 合理定义分布列实现性能优化-分布式聚集

实验介绍

本实验通过分析普通查询过程中存在的性能瓶颈点,通过执行计划的分析找到可能的性能优化点并加以实施,最终达到优化的效果,重点关注分布式聚集相关查询语句的优化。

实验目的

了解通过合理定义分布列实现分布式聚集的性能优化。

实验步骤

步骤1 使用lineitem默认第一列作为分布键进行建表

sql 复制代码
Drop table if exists lineitem; 

CREATE TABLE lineitem (
l_orderkey bigint NOT NULL,
l_partkey bigint NOT NULL,
l_suppkey bigint NOT NULL,
l_linenumber bigint NOT NULL,
l_quantity numeric(15,2) NOT NULL,
l_extendedprice numeric(15,2) NOT NULL,
l_discount numeric(15,2) NOT NULL,
l_tax numeric(15,2) NOT NULL,
l_returnflag character(1) NOT NULL,
l_linestatus character(1) NOT NULL,
l_shipdate date NOT NULL,
l_commitdate date NOT NULL,
l_receiptdate date NOT NULL,
l_shipinstruct character(25) NOT NULL,
l_shipmode character(10) NOT NULL,
l_comment character varying(44) NOT NULL
)
WITH (orientation=row, compression=no)
DISTRIBUTE BY HASH(l_orderkey);

步骤2 导入数据,并收集统计信息

通过 copy 工具导入 lineitem.csv 数据。

sql 复制代码
COPY LINEITEM FROM '/tmp/lineitem_.csv' 
    DELIMITER ',' 
    QUOTE '"' 
    ESCAPE '"' 
    ENCODING 'UTF-8' 
    CSV;

analyze lineitem;

步骤3 执行子查询查看计划耗时详情。

设置参数:
set enable_fast_query_shipping = off;
set enable_stream_operator = on;

该两个参数为会话级,只在本次会话期间生效。

sql 复制代码
EXPLAIN ANALYZE
select
l_partkey as temp_l_partkey, 0.2 * avg(l_quantity) as temp_avg
from
lineitem
group by l_partkey;

从结果可以看到由于分布键和group by的分组字段不匹配,导致需要进行两次聚集操作,一次在本地,一次是按 group by字段重分布之后,再进行汇总。

步骤4 使用group by列作为分布键进行建表

sql 复制代码
CREATE TABLE lineitem_by_partkey
(
l_orderkey bigint NOT NULL,
l_partkey bigint NOT NULL,
l_suppkey bigint NOT NULL,
l_linenumber bigint NOT NULL,
l_quantity numeric(15,2) NOT NULL,
l_extendedprice numeric(15,2) NOT NULL,
l_discount numeric(15,2) NOT NULL,
l_tax numeric(15,2) NOT NULL,
l_returnflag character(1) NOT NULL,
l_linestatus character(1) NOT NULL,
l_shipdate date NOT NULL,
l_commitdate date NOT NULL,
l_receiptdate date NOT NULL,
l_shipinstruct character(25) NOT NULL,
l_shipmode character(10) NOT NULL,
l_comment character varying(44) NOT NULL
)
WITH (orientation=row, compression=no)
DISTRIBUTE BY HASH(l_partkey);

步骤5 导入数据,重新导入数据文件lineitem.csv,更新统计信息。

sql 复制代码
COPY lineitem_by_partkey FROM '/tmp/lineitem_.csv' 
    DELIMITER ',' 
    QUOTE '"' 
    ESCAPE '"' 
    ENCODING 'UTF-8' 
    CSV;

analyze lineitem_by_partkey;

步骤6 执行下列子查询查看计划耗时详情。

设置参数:
set enable_fast_query_shipping = off;
set enable_stream_operator = on;

该两个参数为会话级,只在本次会话期间生效。

sql 复制代码
jiang=# EXPLAIN ANALYZE
select
l_partkey as temp_l_partkey, 0.2 * avg(l_quantity) as temp_avg
from
lineitem_by_partkey
group by l_partkey;
 id |                 operation                 |      A-time       | A-rows  | E-rows  | Peak Memory | A-width | E-width | E-costs  
----+-------------------------------------------+-------------------+---------+---------+-------------+---------+---------+----------
  1 | ->  Streaming (type: GATHER)              | 395.945           |  198962 |  175185 | 82KB        |         |      45 | 20582.17
  2 |    ->  HashAggregate                      | [349.837,371.626] |  198962 |  175185 | [22MB,23MB] | [24,24] |      45 | 13282.80
  3 |       ->  Seq Scan on lineitem_by_partkey | [89.672,90.937]   | 1048576 | 1048576 | [26KB,27KB] |         |      13 | 10659.25
(3 rows)

 Memory Information (identified by plan id) 
--------------------------------------------
 Coordinator Query Peak Memory:
         Query Peak Memory: 1MB
 Datanode:
         Max Query Peak Memory: 28MB
         Min Query Peak Memory: 28MB
(5 rows)

                           User Define Profiling                           
---------------------------------------------------------------------------
 Plan Node id: 1  Track name: coordinator get datanode connection
  (actual time=[0.021, 0.021], calls=[1, 1])
 Plan Node id: 1  Track name: Coordinator serialize plan
  (actual time=[0.668, 0.668], calls=[1, 1])
 Plan Node id: 1  Track name: Coordinator send begin command
  (actual time=[0.001, 0.001], calls=[1, 1])
 Plan Node id: 1  Track name: Coordinator start transaction and send query
  (actual time=[0.050, 0.050], calls=[1, 1])
(8 rows)

                                 ====== Query Summary =====                                 
--------------------------------------------------------------------------------------------
 Datanode executor start time [dn_6004_6005_6006, dn_6007_6008_6009]: [6.318 ms,6.513 ms]
 Datanode executor run time [dn_6007_6008_6009, dn_6001_6002_6003]: [381.451 ms,399.702 ms]
 Datanode executor end time [dn_6007_6008_6009, dn_6001_6002_6003]: [0.017 ms,0.021 ms]
 Coordinator executor start time: 6.450 ms
 Coordinator executor run time: 408.400 ms
 Coordinator executor end time: 0.020 ms
 Planner runtime: 0.187 ms
 Plan size: 3857 byte
 Query Id: 72902018968436769
 Total runtime: 414.882 ms
(10 rows)

此时生成了语句下推的执行计划。为了分析各算子的开销,可设置禁止语句下推,观察CN上的整体计划执行情况:
set enable_fast_query_shipping = off;

这里可以看到,和默认按 l_orderkey 分布不同,此时由于不需要跨 DN 的数据交互,只需要进行一次聚集操作,不需要对数据进行 redistribute,整体性能得到提升。

这部分优化效果主要取决于 DN 本地进行聚集之后 group by 字段的唯一值数量,如果本身group by 列和分布列相关性较好,各 DN 上 group by字段唯一值较少,则数据重分布和第二次聚集操作的开销也会相对较小。

实验总结

本实验通过调整数据表分布键的方法,对子查询进行了调优,相同数据量下,选择和 group by

字段相同的分布键将有效提升子查询分布式聚集性能。

相关推荐
露天赏雪5 小时前
Java 高并发编程实战:从线程池到分布式锁,解决生产环境并发问题
java·开发语言·spring boot·分布式·后端·mysql
没有bug.的程序员7 小时前
Spring Boot 事务管理:@Transactional 失效场景、底层内幕与分布式补偿实战终极指南
java·spring boot·分布式·后端·transactional·失效场景·底层内幕
LuminescenceJ8 小时前
GoEdge 开源CDN 架构设计与工作原理分析
分布式·后端·网络协议·网络安全·rpc·开源·信息与通信
组合缺一11 小时前
论 AI Skills 分布式发展的必然性:从单体智能到“云端大脑”的跃迁
java·人工智能·分布式·llm·mcp·skills
shepherd12612 小时前
深度剖析SkyWalking:从内核原理到生产级全链路监控实战
分布式·后端·skywalking
h7ml14 小时前
基于 RabbitMQ 构建异步化淘客订单处理流水线:解耦、削峰与失败重试
分布式·rabbitmq·ruby
夜月蓝汐14 小时前
分布式监控SkyWalking链路追踪
分布式·skywalking
shandongtianhe14 小时前
分布式光伏气象站:实现对光伏电站所处环境的多参数、实时化、高精度监测
分布式
源代码•宸14 小时前
分布式理论基础——Raft算法
经验分享·分布式·后端·算法·golang·集群·raft
J_liaty14 小时前
XXL-Job 实现分布式定时任务
分布式·xxl-job