达梦分布式集群DPC_并行介绍
1 分布式并行执行简介
在数据洪流中,数据的处理速度变的越来越关键,单台机器的处理能力早已触达天花板。
并行执行的核心思想:
将一个复杂的查询任务(Query)分解成多个独立的子任务(Subtask),并将这些子任务分配给多个处理器同时执行,最后将结果汇总。
关键点:
利用任务拆分(一变多),充分利用 CPU核数、内存、存储 I/O 性能、网络带宽等资源
2 并行分类
分布式的并行,大体可以分为两种
1.并行度跟子表数绑定
一个线程的扫描单位是一个分区子表
比如一个站点的子表数为3,那么这个站点的最大并行度为3,最常见的是分区智能连接场景
2.表内并行
一个线程的扫描范围是一个分区子表中的一段连续数据,将表数据分成多个块
2.1 并行度跟子表数绑定
DPC架构为4个站点
MP MP_RAFT
BP1 RAFT_1
BP2 RAFT_2
SP RAFT_SP1
2.1.1 分区智能连接
--建表,创建两个hash分区表,每个BP有1个子表
CREATE TABLE "TEST01"
("ID" VARCHAR2(36) NOT NULL,"DATE" TIMESTAMP(0) NOT NULL) PARTITION BY HASH("ID") PARTITIONS 2;
INSERT INTO TEST01 VALUES( '1','2024-01-01 00:00:00');
INSERT INTO TEST01 VALUES( '2','2025-01-01 00:00:00');
INSERT INTO TEST01 VALUES( '3','2026-01-01 00:00:00'); COMMIT;
stat 100 on TEST01(ID);stat 100 on TEST01(DATE);
CREATE TABLE "TEST02"
("ID" VARCHAR2(36) NOT NULL,"DATE" TIMESTAMP(0) NOT NULL)PARTITION BY HASH("ID")PARTITIONS 2;
INSERT INTO TEST02 VALUES( '1','2024-01-01 00:00:00');
INSERT INTO TEST02 VALUES( '2','2025-01-01 00:00:00'); COMMIT;
stat 100 on TEST02(ID);stat 100 on TEST02(DATE);
EXPLAIN select *from TEST01 INNER JOIN TEST02 ON TEST01.ID=TEST02.ID;
1 NSET2:[1, 2, 122]
2 ERECV:[1, 2, 122];stask_no(-1), l_stask_no(0), n_key(0), in_turn(0), trig(0)
3 ESEND:[1, 2, 122];stask_no(0), type(DIRECT), sites(2:1,1:1), sql_invoke(0), pwj_opt(0), table(-); INFO_BITS(0xc)
4 GI:[1, 2, 122];policy(PART_UNIT), gi_unit[0..1], scan_type[0](FULL), dynamic_pll[1]
5 PRJT2:[1, 2, 122];exp_num(4), is_atom(FALSE)
6 HASH2 INNER JOIN:[1, 2, 122];KEY_NUM(1); KEY(TEST02.ID=TEST01.ID) KEY_NULL_EQU(0)
7 CSCN2:[1, 2, 61];INDEX33569707(TEST02); btr_scan(1)
8 CSCN2:[1, 3, 61];INDEX33569704(TEST01); btr_scan(1)
核心为:
因为两个表分区方式相同的原因,TEST02.ID=TEST01.ID的数据,肯定在同一个地方,避免了数据跨节点传输,所以可以进行分区智能连接操作
并行分析:
GI:[1, 2, 122];policy(PART_UNIT),PART_UNIT指以一级分区子表为单位扫描,访问粒度固定为 一级分区子表。每个工作线程一次处理 一个完整的一级分区子表
sites(2:1,1:1),指1和2号站点(BP1、2)的并行度都为1,每个站点有一个线程处理任务
线程分析:
--查询各个站点号的执行线程情况
select sf_get_ep_seqno(rowid) 站点号, count(*) 线程数
from v$dpc_stask_thrd
where exec_id = 12603943 and stask_no = 0 group by sf_get_ep_seqno(rowid);
站点号,线程数
1 1
2 1
可以分析出,两个BP站点号的线程数为1
GI的策略为PART_UNIT或者有SQC字样的,都是以子表为单位扫描,并行度受子表数限制
2.1.2 并行插入
--建表和插入数据
create table TEST1(C1 int,C2 varchar) partition by hash(C1) partitions 4;
create table TEST2(C1 int,C2 varchar) partition by hash(C1) partitions 16;
create table TEST3(C1 int,C2 varchar) partition by hash(C1) subpartition by hash(c2) subpartitions 8 partitions 8;
insert into TEST1 select level,level from dual connect by level<=1000;
commit;
--打开并行插入语句
insert into TEST2 /*+ PARALLEL_INS(TEST2) PARALLEL(32) */ select * from TEST1;
--查看线程数
站点号,线程数
1 8
2 8
因为并行度跟子表数绑定,TEST2每个BP有8个子表,所以单个站点插入最大并行度为8
2.2 表内并行
--建表和初始化数据,只存储在单个站点上
CREATE TABLE T1(C1 INT, C2 INT) STORAGE(ON TS_RAFT_1);
CREATE TABLE T2(C1 INT, C2 INT) STORAGE(ON TS_RAFT_1);
INSERT INTO T1 SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 1000000;
INSERT INTO T2 SELECT LEVEL, LEVEL FROM DUAL CONNECT BY LEVEL <= 1000000;
COMMIT;
STAT ON T1;
STAT ON T2;
STAT 100 ON T1(C1);STAT 100 ON T1(C2);
STAT 100 ON T2(C1);STAT 100 ON T2(C2);
--开启DPC单站点并行优化
EXPLAIN SELECT /*+PARALLEL(10) DPC(1 L_DIS_R_DIS) DPC_OPT_FLAG(262143)*/ COUNT(*) FROM T1, T2 WHERE T1.C1 = T2.C1;
#NSET2: [404, 1, 8]
#ERECV: [404, 1, 8]; stask_no(-1), l_stask_no(3), n_key(0), in_turn(0), trig(0)
#ESEND: [404, 1, 8]; stask_no(3), type(DIRECT), sites(1:1), sql_invoke(0), pwj_opt(0), table(-); INFO_BITS(0x8)
#PRJT2: [404, 1, 8]; exp_num(1), is_atom(FALSE)
#AAGR2: [404, 1, 8]; grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0)
#ERECV: [404, 1, 8]; stask_no(3), l_stask_no(1), n_key(0), in_turn(0), trig(0)
#ESEND: [404, 1, 8]; stask_no(1), type(DIRECT), sites(1:10), sql_invoke(0), pwj_opt(0), table(-); INFO_BITS(0xc)
#AAGR2: [404, 1, 8]; grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0)
#HASH2 INNER JOIN: [404, 1000000, 8]; KEY_NUM(1); KEY(T1.C1=T2.C1) KEY_NULL_EQU(0)
#ERECV: [105, 1000000, 4]; stask_no(1), l_stask_no(0), n_key(0), in_turn(0), trig(0)
#ESEND: [105, 1000000, 4]; stask_no(0), type(N_DEST), sites(1:5), sql_invoke(0), pwj_opt(0), table(-) ,keys(T1.C1) ; INFO_BITS(0xc)
#GI: [105, 1000000, 4]; policy(RANDOM), gi_unit[0..0], scan_type[0](FULL)
#CSCN2: [105, 1000000, 4]; INDEX33556067(T1); btr_scan(1)
#ERECV: [105, 1000000, 4]; stask_no(1), l_stask_no(2), n_key(0), in_turn(0), trig(0)
#ESEND: [105, 1000000, 4]; stask_no(2), type(N_DEST), sites(1:7), sql_invoke(0), pwj_opt(0), table(-) ,keys(T2.C1) ; INFO_BITS(0x8)
#GI: [105, 1000000, 4]; policy(RANDOM), gi_unit[0..0], scan_type[0](FULL)
#CSCN2: [105, 1000000, 4]; INDEX33556069(T2); btr_scan(1)
--不启用单站点并行优化
EXPLAIN SELECT /*+PARALLEL(10) DPC(1 L_DIS_R_DIS) DPC_OPT_FLAG(131071)*/ COUNT(*) FROM T1, T2 WHERE T1.C1 = T2.C1;
1 NSET2:[404, 1, 8]
2 ERECV:[404, 1, 8];stask_no(-1), l_stask_no(0), n_key(0), in_turn(0), trig(0)
3 ESEND:[404, 1, 8];stask_no(0), type(DIRECT), sites(1:1), sql_invoke(0), pwj_opt(0), table(-); INFO_BITS(0xc)
4 PRJT2:[404, 1, 8];exp_num(1), is_atom(FALSE)
5 AAGR2:[404, 1, 8];grp_num(0), sfun_num(1), distinct_flag[0]; slave_empty(0)
6 HASH2 INNER JOIN:[404, 1000000, 8];KEY_NUM(1); KEY(T1.C1=T2.C1) KEY_NULL_EQU(0)
7 CSCN2:[105, 1000000, 4];INDEX33569847(T1); btr_scan(1)
8 CSCN2:[105, 1000000, 4];INDEX33569848(T2); btr_scan(1)
并行分析:
policy(RANDOM):当采用RANDOM方式扫描数据时,能使用表内并行,扫描粒度为数据块
sites(1:1):没有表内并行时,同个站点上的普通表,只能一个线程扫描任务
3 并行总结
并行执行通过充分利用资源,以实现降低 SQL 执行时间的目标。
【可以是充分利用多个服务器资源,也可以充分利用单个服务器内的资源】,就对应上并行的两种分类
1.并行度跟子表数绑定,想增加并行就需要增加子表数,子表分配到多台服务器来利用多个服务器资源
2.表内并行,单个站点内,将扫描粒度进一步细化为数据块,进一步提升并行度,但是线程之间的协调开销会加大
当数据扫描量大(高负载sql),SQL执行内部并发度低,具备充足的硬件资源时,能够增加并行来提升性能
注意
某些模块是不能采用并行执行的,比如有自定义函数时,优化器无法分析出这个函数的行为,为了保证结果的正确性,只能单线程运行
更多其他数据库相关专栏:
1.数据库优化
数据库优化基本思路、索引详解、执行计划、统计信息、CBO原理、单表优化、多表优化、分布式优化、子查询、优化案例等
数据库优化(sql优化)专栏连接
2.达梦分布式数据库:
部署详细步骤(DEM)、备份还原实战、核心特性理解、使用心得、表分区方式详细介绍、表分区最佳实践、DPC架构详解等
达梦分布式DPC专栏连接
3.应用开发类
jdbc、hibernate、ibatis、mybatis、MyBatis-Plus、Spring、中间件mycat、Sharding-JDBC等
达梦数据库应用开发专栏连接
1265

被折叠的 条评论
为什么被折叠?



