searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

性能优化最佳实践

2024-11-08 09:21:28
11
0

1.1 SQL优化最佳实践

1.1.1 查询带分布键条件

通过explain查看执行计划,查看SQL语句是否使用到分布键,DN下发DN情况可通过Node/s: 关键字来查看。

如果使用了分布键,那么SQL只会下发到分布键对应的某个DN节点。

如果没有使用分布键,那么SQL会下发到所有DN节点。

没有带分布键的SQL,因为下发到了所有DN节点,消耗了更多的连接资源、计算资源,应尽量避免使用。

某个表的SQL语句可能有不同的where条件,在SQL优化时,应尽量确保高频并发的SQL语句是带了分布键条件。

例如,teledb_1表的分布键f2,下面的SQL where条件为f1=1,没有带分布键条件,那么SQL将下发到所有DN节点执行。

teledb=# explain select * from teledb_1 where f1=1;

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_1 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f1 = 1)

(6 rows) 

下面的SQLwhere条件为f2=1,带了分布键条件,SQL只下发到了f2=1所在的DN节点dn001

teledb=# explain select * from teledb_1 where f2=1;

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_1 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f2 = 1)

(6 rows)

1.1.2 关联查询使用分布键关联

多表关联时,通过explain查看执行计划,查看SQL语句是否使用分布键(前面已介绍),查看SQL关联是否使用到了分布键。

如果两表关联都使用到了分布键,那么两表关联可以在dn节点内完成,不需要在dn节点之间交互数据;如果其中一张表没有用分布键,那么两表关联不能在dn节点内完成,该表需要在dn节点之间交互数据;如果两张表都没有使用分布键,那么两张表都需要在dn节点之间交互数据。

两表关联时,应优先使用两表的分布键关联,尽量保证高频并发的SQL都使用了分布键关联;其次至少有一张表用到了分布键,也可以减少一次数据重分布;两张表都没有用到分布键的场景应尽量避免。同时,两表关联时如果只能有一个表带分布键,那么更大的表、或查询结果集更大的表优先使用到分布键,让小一点的表去重分布数据。

在执行计划中,如果DN之间有数据重分布,那么执行计划中会有这样的关键字Distribute results by S: f1,这里表示按f1进行数据重分布。

例如,teledb_1的分布键为f2teledb_2的分布键为f1,下面的SQL,两表关联时teledb_1没有用到分布键,两表关联不能在dn节点内完成,需要dn节点之间发起数据交互(重分布),teledb_1在完成表扫描后发起了按f1字段重分布的动作,对应执行计划中的Distribute results by S: f1

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

------------------------------------------------------------------------------------------------

Remote Subquery Scan on all (dn001,dn002) (cost=29.80..186.32 rows=3872 width=40)

 -> Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 Distribute results by S: f1

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=18.80..18.80 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(8 rows) 

例如下面的SQLteledb_1teledb_2关联时都用到了分布键,那么两表关联可以在dn节点内完成,不需要在dn节点之间交互数据。

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f2=teledb_2.f1 ;

 QUERY PLAN

---------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Hash Join (cost=18904.69..46257.08 rows=500564 width=14)

 Hash Cond: (teledb_1.f2 = teledb_2.f1)

 -> Seq Scan on teledb_1 (cost=0.00..9225.64 rows=500564 width=14)

 -> Hash (cost=9225.64..9225.64 rows=500564 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..9225.64 rows=500564 width=4)

(7 rows)

1.1.3 使用索引提高查询效率

通过explain查看执行计划,查看SQL语句是否使用了索引,Seq Scan表示对表进行了全表扫描,而如Index ScanIndex Only Scan则表示使用了索引扫描。

通常情况下,使用索引可以加速查询速度,但索引也会增加数据更新的开销,在数据量较小时,优化器也可能会使用全表扫描代替索引扫描。

例如,下面的SQL语句,使用了Parallel Seq Scan并行全表扫描。

teledb=# explain select * from teledb_2 where f3='1';

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_2 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f3 = '1'::text)

(6 rows)

f2字段上创建索引后,下面的SQL语句,使用了Index Scan索引扫描。

teledb=# create index teledb_2_f2_idx on teledb_2(f2);

CREATE INDEX

postgres=# explain select * from teledb_2 where f2=1;

 QUERY PLAN

-------------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Index Scan using teledb_2_f2_idx on teledb_2 (cost=0.42..4.44 rows=1 width=14)

 Index Cond: (f2 = 1)

(4 rows)

当然,按SQL优化原则,上述SQL语句where条件都没有带分布键,导致SQL下发到了所有DN节点,建议尝试优化为带分布键查询。

1.1.4 使用并行提高查询效率

在大表查询时,为充分利用服务器资源,可以尝试开启并行,多进程并发查询,提升查询效率。在执行计划中,算子前增加关键字Partial,同时有关键字 Workers Planned: xx,表示SQL使用了并行。

例如下面的SQL,未开启并行。

teledb=# explain select count(1) from teledb_1;

 QUERY PLAN

---------------------------------------------------------------------------------------

Finalize Aggregate (cost=118.81..118.83 rows=1 width=8)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=118.80..118.81 rows=1 width=0)

 -> Partial Aggregate (cost=18.80..18.81 rows=1 width=8)

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=0)

(4 rows)

下面是开启并行查询后的执行计划。

teledb=# explain select count(1) from teledb_1;

 QUERY PLAN

----------------------------------------------------------------------------------------------------

Parallel Finalize Aggregate (cost=14728.45..14728.46 rows=1 width=8)

 -> Parallel Remote Subquery Scan on all (dn001,dn002) (cost=14728.33..14728.45 rows=1 width=0)

 -> Gather (cost=14628.33..14628.44 rows=1 width=8)

 Workers Planned: 2

 -> Partial Aggregate (cost=13628.33..13628.34 rows=1 width=8)

 -> Parallel Seq Scan on teledb_1 (cost=0.00..12586.67 rows=416667 width=0)

(6 rows)

建议不要全局开启并行,仅在需要开启并行的具体SQL上开启,可通过会话级设置并行,或hint方式指定并行。

会话级设置如:

set max_parallel_workers_per_gather=2;

执行SQL;

set max_parallel_workers_per_gather=0;

1.1.5 根据需要设置关联发生的节点

多表关联的逻辑默认是在DN节点执行,在发生重分布后,可能会因为重分布原因性能明显下降。

针对此问题,TeleDB支持通过参数prefer_olap设置,可以选择将关联逻辑上拉到CN节点执行,避免DN之间的重分布。参数prefer_olap默认为on,表示关联下推到DN执行,off则表示关联上拉到DN执行。

这里需要注意,设置关联上拉CN节点执行,需要提前做好评估,如果上拉数据量过大,大量并发SQL发起上拉数据到CN动作,会导致CN节点负载过高,甚至OOM

通常可以在TP类业务中可以针对SQL会话级设置上拉,性能会有所提升,同时CN节点应配置较大的资源,避免OOM发生。

例如,下面的SQLteledb_1关联没有用到分布键,发生了重分布。

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

------------------------------------------------------------------------------------------------

Remote Subquery Scan on all (dn001,dn002) (cost=29.80..186.32 rows=3872 width=40)

 -> Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 Distribute results by S: f1

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=18.80..18.80 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(8 rows)

设置 prefer_olap=off后,关联上拉到CN上执行,重分布消失。

执行计划如下:

teledb=# set prefer_olap to off;

SET

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

-----------------------------------------------------------------------------------------------

Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=126.72..126.72 rows=880 width=4)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..126.72 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(7 rows)

0条评论
0 / 1000
c****f
1文章数
0粉丝数
c****f
1 文章 | 0 粉丝
c****f
1文章数
0粉丝数
c****f
1 文章 | 0 粉丝
原创

性能优化最佳实践

2024-11-08 09:21:28
11
0

1.1 SQL优化最佳实践

1.1.1 查询带分布键条件

通过explain查看执行计划,查看SQL语句是否使用到分布键,DN下发DN情况可通过Node/s: 关键字来查看。

如果使用了分布键,那么SQL只会下发到分布键对应的某个DN节点。

如果没有使用分布键,那么SQL会下发到所有DN节点。

没有带分布键的SQL,因为下发到了所有DN节点,消耗了更多的连接资源、计算资源,应尽量避免使用。

某个表的SQL语句可能有不同的where条件,在SQL优化时,应尽量确保高频并发的SQL语句是带了分布键条件。

例如,teledb_1表的分布键f2,下面的SQL where条件为f1=1,没有带分布键条件,那么SQL将下发到所有DN节点执行。

teledb=# explain select * from teledb_1 where f1=1;

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_1 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f1 = 1)

(6 rows) 

下面的SQLwhere条件为f2=1,带了分布键条件,SQL只下发到了f2=1所在的DN节点dn001

teledb=# explain select * from teledb_1 where f2=1;

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_1 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f2 = 1)

(6 rows)

1.1.2 关联查询使用分布键关联

多表关联时,通过explain查看执行计划,查看SQL语句是否使用分布键(前面已介绍),查看SQL关联是否使用到了分布键。

如果两表关联都使用到了分布键,那么两表关联可以在dn节点内完成,不需要在dn节点之间交互数据;如果其中一张表没有用分布键,那么两表关联不能在dn节点内完成,该表需要在dn节点之间交互数据;如果两张表都没有使用分布键,那么两张表都需要在dn节点之间交互数据。

两表关联时,应优先使用两表的分布键关联,尽量保证高频并发的SQL都使用了分布键关联;其次至少有一张表用到了分布键,也可以减少一次数据重分布;两张表都没有用到分布键的场景应尽量避免。同时,两表关联时如果只能有一个表带分布键,那么更大的表、或查询结果集更大的表优先使用到分布键,让小一点的表去重分布数据。

在执行计划中,如果DN之间有数据重分布,那么执行计划中会有这样的关键字Distribute results by S: f1,这里表示按f1进行数据重分布。

例如,teledb_1的分布键为f2teledb_2的分布键为f1,下面的SQL,两表关联时teledb_1没有用到分布键,两表关联不能在dn节点内完成,需要dn节点之间发起数据交互(重分布),teledb_1在完成表扫描后发起了按f1字段重分布的动作,对应执行计划中的Distribute results by S: f1

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

------------------------------------------------------------------------------------------------

Remote Subquery Scan on all (dn001,dn002) (cost=29.80..186.32 rows=3872 width=40)

 -> Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 Distribute results by S: f1

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=18.80..18.80 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(8 rows) 

例如下面的SQLteledb_1teledb_2关联时都用到了分布键,那么两表关联可以在dn节点内完成,不需要在dn节点之间交互数据。

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f2=teledb_2.f1 ;

 QUERY PLAN

---------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Hash Join (cost=18904.69..46257.08 rows=500564 width=14)

 Hash Cond: (teledb_1.f2 = teledb_2.f1)

 -> Seq Scan on teledb_1 (cost=0.00..9225.64 rows=500564 width=14)

 -> Hash (cost=9225.64..9225.64 rows=500564 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..9225.64 rows=500564 width=4)

(7 rows)

1.1.3 使用索引提高查询效率

通过explain查看执行计划,查看SQL语句是否使用了索引,Seq Scan表示对表进行了全表扫描,而如Index ScanIndex Only Scan则表示使用了索引扫描。

通常情况下,使用索引可以加速查询速度,但索引也会增加数据更新的开销,在数据量较小时,优化器也可能会使用全表扫描代替索引扫描。

例如,下面的SQL语句,使用了Parallel Seq Scan并行全表扫描。

teledb=# explain select * from teledb_2 where f3='1';

 QUERY PLAN

--------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Gather (cost=1000.00..7827.20 rows=1 width=14)

 Workers Planned: 2

 -> Parallel Seq Scan on teledb_2 (cost=0.00..6827.10 rows=1 width=14)

 Filter: (f3 = '1'::text)

(6 rows)

f2字段上创建索引后,下面的SQL语句,使用了Index Scan索引扫描。

teledb=# create index teledb_2_f2_idx on teledb_2(f2);

CREATE INDEX

postgres=# explain select * from teledb_2 where f2=1;

 QUERY PLAN

-------------------------------------------------------------------------------------

Remote Fast Query Execution (cost=0.00..0.00 rows=0 width=0)

 Node/s: dn001, dn002

 -> Index Scan using teledb_2_f2_idx on teledb_2 (cost=0.42..4.44 rows=1 width=14)

 Index Cond: (f2 = 1)

(4 rows)

当然,按SQL优化原则,上述SQL语句where条件都没有带分布键,导致SQL下发到了所有DN节点,建议尝试优化为带分布键查询。

1.1.4 使用并行提高查询效率

在大表查询时,为充分利用服务器资源,可以尝试开启并行,多进程并发查询,提升查询效率。在执行计划中,算子前增加关键字Partial,同时有关键字 Workers Planned: xx,表示SQL使用了并行。

例如下面的SQL,未开启并行。

teledb=# explain select count(1) from teledb_1;

 QUERY PLAN

---------------------------------------------------------------------------------------

Finalize Aggregate (cost=118.81..118.83 rows=1 width=8)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=118.80..118.81 rows=1 width=0)

 -> Partial Aggregate (cost=18.80..18.81 rows=1 width=8)

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=0)

(4 rows)

下面是开启并行查询后的执行计划。

teledb=# explain select count(1) from teledb_1;

 QUERY PLAN

----------------------------------------------------------------------------------------------------

Parallel Finalize Aggregate (cost=14728.45..14728.46 rows=1 width=8)

 -> Parallel Remote Subquery Scan on all (dn001,dn002) (cost=14728.33..14728.45 rows=1 width=0)

 -> Gather (cost=14628.33..14628.44 rows=1 width=8)

 Workers Planned: 2

 -> Partial Aggregate (cost=13628.33..13628.34 rows=1 width=8)

 -> Parallel Seq Scan on teledb_1 (cost=0.00..12586.67 rows=416667 width=0)

(6 rows)

建议不要全局开启并行,仅在需要开启并行的具体SQL上开启,可通过会话级设置并行,或hint方式指定并行。

会话级设置如:

set max_parallel_workers_per_gather=2;

执行SQL;

set max_parallel_workers_per_gather=0;

1.1.5 根据需要设置关联发生的节点

多表关联的逻辑默认是在DN节点执行,在发生重分布后,可能会因为重分布原因性能明显下降。

针对此问题,TeleDB支持通过参数prefer_olap设置,可以选择将关联逻辑上拉到CN节点执行,避免DN之间的重分布。参数prefer_olap默认为on,表示关联下推到DN执行,off则表示关联上拉到DN执行。

这里需要注意,设置关联上拉CN节点执行,需要提前做好评估,如果上拉数据量过大,大量并发SQL发起上拉数据到CN动作,会导致CN节点负载过高,甚至OOM

通常可以在TP类业务中可以针对SQL会话级设置上拉,性能会有所提升,同时CN节点应配置较大的资源,避免OOM发生。

例如,下面的SQLteledb_1关联没有用到分布键,发生了重分布。

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

------------------------------------------------------------------------------------------------

Remote Subquery Scan on all (dn001,dn002) (cost=29.80..186.32 rows=3872 width=40)

 -> Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 Distribute results by S: f1

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=18.80..18.80 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(8 rows)

设置 prefer_olap=off后,关联上拉到CN上执行,重分布消失。

执行计划如下:

teledb=# set prefer_olap to off;

SET

teledb=# explain select teledb_1.* from teledb_1,teledb_2 where teledb_1.f1=teledb_2.f1 ;

 QUERY PLAN

-----------------------------------------------------------------------------------------------

Hash Join (cost=29.80..186.32 rows=3872 width=40)

 Hash Cond: (teledb_1.f1 = teledb_2.f1)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..158.40 rows=880 width=40)

 -> Seq Scan on teledb_1 (cost=0.00..18.80 rows=880 width=40)

 -> Hash (cost=126.72..126.72 rows=880 width=4)

 -> Remote Subquery Scan on all (dn001,dn002) (cost=100.00..126.72 rows=880 width=4)

 -> Seq Scan on teledb_2 (cost=0.00..18.80 rows=880 width=4)

(7 rows)

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0