共计 5979 个字符,预计需要花费 15 分钟才能阅读完成。
随着数字化过程的放慢,寰球数据量呈指数级增长,对数据库系统的性能提出了微小的挑战。优化器作为数据库管理系统中的关键技术,对数据库性能和效率具备重要影响,它通过对用户的查问申请进行解析和优化来生成高效的执行打算,进而疾速返回查问后果。然而,同一条 SQL 语句在不同的优化决策下可能会产生数量级的性能差别。随着数据规模和查问复杂性的减少,优化器的一直倒退和翻新将成为数据库系统继续晋升性能的重要方向,也是数据库系统的最强有力的竞争力之一。
针对云原生和分布式场景,云原生虚构数仓 PieCloudDB Database 设计与打造了新一代优化器:「达奇」。这个命名灵感来自于游戏《荒野大镖客》中的一个 NPC 角色,他的口头禅“I have a plan”与优化器的性能十分符合。
优化器「达奇」在 PieCloudDB 中实现了许多优化个性,通过生成高质量的查问打算,充当数据库系统的“智囊团”,确保用户的查问性能和效率。「达奇」通过智能地剖析查问语句、优化查问打算以及利用分布式数据存储和计算能力,实现了更疾速、更高效的查询处理。
拓数派吉祥物「派派」
1 汇集操作与汇集下推
明天,咱们将具体介绍「达奇」的全新性能:汇集下推。在古代的数据库系统中,汇集操作(Aggregate)是十分常见的一种操作类型。通过汇集操作,能够把多行数据合并成一行,并对其进行统计、求和、求均值等计算。
在传统的查问执行过程中,聚合操作通常在查问后果返回后进行,须要将所有数据传输至查问引擎进行聚合计算。然而,对于大规模数据集和简单查问,这种形式可能导致查问性能低下、计算负载过高和计算成本低廉等问题。
为了解决这些问题,PieCloudDB 优化器「达奇」打造了汇集下推(Aggregate Pushdown)这一性能,经测试,在很多场景下,汇集下推性能会获得百倍甚至千倍的性能晋升。
2 汇集下推原理
汇集下推(Pushdown Aggregation)是一种数据库查问优化技术,通过将聚合操作下推至数据源,缩小数据传输和解决的开销,从而进步查问性能和效率。
汇集下推的实现原理是在查问执行过程中尽可能早地进行聚合操作,并将聚合操作下推至数据源进行解决。具体而言,当查问打算生成时,优化器会将聚合操作下推至数据源,以便在数据源处进行聚合计算。这样能够缩小数据传输量,加重查问引擎的累赘,并利用数据源的计算能力进行部分聚合。
上面咱们用一个简略的图示,来解说汇集下推的次要实现原理:
有无「汇集下推」比照
上图中,左图是没有汇集下推的执行流程,右图是有汇集下推时的执行流程。在左图没有汇集下推的状况下,表 T1 和 T2 会先做连贯操作,并在连贯之后的数据集上实现汇集操作。
而在右图有汇集下推的状况下,会在对表 T1 和 T2 进行连贯操作之前,先对表 T1 做一次汇集操作。这样能够在某些场景下使得连贯操作时表 T1 中参加的数据量极大的缩小,从而显著进步查问性能。为了能精确地进步查问效率,以上两种执行计划在「达奇」中都会生成,最初会依据代价模型的估算抉择代价较小的执行计划。
当有更多的表参加连贯时,「达奇」会尝试把汇集操作下推到不同的连贯层,通过代价的比拟来选定最优的下推地位。
3 汇集下推演示实例
上面,咱们通过一个查问实例来看一下汇集下推的成果。首先,咱们通过上面语句来创立测试用表:
CREATE TABLE t (x int, y int);
INSERT INTO t SELECT i % 30, i % 30 FROM generate_series(1, 10240) i;
ANALYZE t;
测试所用的查问如下:
SELECT t1.x, sum(t2.y + t3.y), count(*) FROM t t1
JOIN t t2 ON t1.x = t2.x JOIN t t3 ON t2.x = t3.x
GROUP BY t1.x;
当没有汇集下推时,查问打算如下:
EXPLAIN (ANALYZE, COSTS OFF)
SELECT t1.x, sum(t2.y + t3.y), count(*) FROM t t1 JOIN t t2 ON t1.x = t2.x JOIN t t3 ON t2.x = t3.x GROUP BY t1.x;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3) (actual time=153884.859..274102.066 rows=30 loops=1)
-> HashAggregate (actual time=274100.004..274100.011 rows=12 loops=1)
Group Key: t1.x
Peak Memory Usage: 0 kB
-> Hash Join (actual time=38.717..100579.782 rows=477571187 loops=1)
Hash Cond: (t1.x = t3.x)
Extra Text: (seg0) Hash chain length 341.4 avg, 342 max, using 12 of 131072 buckets.
-> Hash Join (actual time=2.088..429.203 rows=1398787 loops=1)
Hash Cond: (t1.x = t2.x)
Extra Text: (seg0) Hash chain length 341.4 avg, 342 max, using 12 of 131072 buckets.
-> Redistribute Motion 3:3 (slice2; segments: 3) (actual time=0.044..4.590 rows=4097 loops=1)
Hash Key: t1.x
-> Seq Scan on t t1 (actual time=1.382..32.683 rows=3496 loops=1)
-> Hash (actual time=1.760..1.761 rows=4097 loops=1)
Buckets: 131072 Batches: 1 Memory Usage: 1185kB
-> Redistribute Motion 3:3 (slice3; segments: 3) (actual time=0.049..0.922 rows=4097 loops=1)
Hash Key: t2.x
-> Seq Scan on t t2 (actual time=1.628..32.837 rows=3496 loops=1)
-> Hash (actual time=36.153..36.153 rows=4097 loops=1)
Buckets: 131072 Batches: 1 Memory Usage: 1185kB
-> Redistribute Motion 3:3 (slice4; segments: 3) (actual time=3.918..35.169 rows=4097 loops=1)
Hash Key: t3.x
-> Seq Scan on t t3 (actual time=1.380..30.316 rows=3496 loops=1)
Planning Time: 8.810 ms
(slice0) Executor memory: 257K bytes.
(slice1) Executor memory: 2484K bytes avg x 3 workers, 2570K bytes max (seg0). Work_mem: 1185K bytes max.
(slice2) Executor memory: 32840K bytes avg x 3 workers, 32841K bytes max (seg0).
(slice3) Executor memory: 32860K bytes avg x 3 workers, 32860K bytes max (seg0).
(slice4) Executor memory: 32860K bytes avg x 3 workers, 32860K bytes max (seg0).
Memory used: 128000kB
Optimizer: Postgres query optimizer
Execution Time: 274130.589 ms
(32 rows)
而当有汇集下推时,查问打算如下:
EXPLAIN (ANALYZE, COSTS OFF)
SELECT t1.x, sum(t2.y + t3.y), count(*) FROM t t1 JOIN t t2 ON t1.x = t2.x JOIN t t3 ON t2.x = t3.x GROUP BY t1.x;
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------
Gather Motion 3:1 (slice1; segments: 3) (actual time=835.755..836.406 rows=30 loops=1)
-> Finalize GroupAggregate (actual time=834.227..835.432 rows=12 loops=1)
Group Key: t1.x
-> Sort (actual time=834.031..834.441 rows=4097 loops=1)
Sort Key: t1.x
Sort Method: quicksort Memory: 1266kB
-> Redistribute Motion 3:3 (slice2; segments: 3) (actual time=812.139..830.706 rows=4097 loops=1)
Hash Key: t1.x
-> Hash Join (actual time=810.536..828.097 rows=3496 loops=1)
Hash Cond: (t1.x = t2.x)
Extra Text: (seg0) Hash chain length 1.0 avg, 1 max, using 30 of 131072 buckets.
-> Seq Scan on t t1 (actual time=1.689..16.674 rows=3496 loops=1)
-> Hash (actual time=808.497..808.498 rows=30 loops=1)
Buckets: 131072 Batches: 1 Memory Usage: 1026kB
-> Broadcast Motion 3:3 (slice3; segments: 3) (actual time=461.065..808.466 rows=30 loops=1)
-> Partial HashAggregate (actual time=810.026..810.033 rows=12 loops=1)
Group Key: t2.x
Peak Memory Usage: 0 kB
-> Hash Join (actual time=28.070..331.181 rows=1398787 loops=1)
Hash Cond: (t2.x = t3.x)
Extra Text: (seg0) Hash chain length 341.4 avg, 342 max, using 12 of 262144 buckets.
-> Redistribute Motion 3:3 (slice4; segments: 3) (actual time=0.040..1.270 rows=4097 loops=1)
Hash Key: t2.x
-> Seq Scan on t t2 (actual time=1.449..19.963 rows=3496 loops=1)
-> Hash (actual time=27.834..27.835 rows=4097 loops=1)
Buckets: 262144 Batches: 1 Memory Usage: 2209kB
-> Redistribute Motion 3:3 (slice5; segments: 3) (actual time=3.836..27.025 rows=4097 loops=1)
Hash Key: t3.x
-> Seq Scan on t t3 (actual time=1.537..23.654 rows=3496 loops=1)
Planning Time: 14.425 ms
(slice0) Executor memory: 328K bytes.
(slice1) Executor memory: 408K bytes avg x 3 workers, 514K bytes max (seg0). Work_mem: 450K bytes max.
(slice2) Executor memory: 33951K bytes avg x 3 workers, 33952K bytes max (seg0). Work_mem: 1026K bytes max.
(slice3) Executor memory: 2298K bytes avg x 3 workers, 2341K bytes max (seg0). Work_mem: 2209K bytes max.
(slice4) Executor memory: 32860K bytes avg x 3 workers, 32860K bytes max (seg0).
(slice5) Executor memory: 32860K bytes avg x 3 workers, 32860K bytes max (seg0).
Memory used: 128000kB
Optimizer: Postgres query optimizer
Execution Time: 865.305 ms
(39 rows)
通过两个查问打算的比照,能够看到,当没有汇集下推时(查问打算 1),须要先实现所有的连贯操作,再在连贯的数据集上进行汇集操作。而汇集下推(查问打算 2)能够把汇集操作下推到最优的连贯层,从而缩小后续连贯操作的数据量,能够显著地晋升性能。
在这个例子中,「达奇」把汇集操作下推到了 t2 和 t3 连贯之后,与 t1 连贯之前。通过比照这两个执行工夫,咱们能够看到 执行工夫从之前的 274130.589 ms 升高到了 865.305 ms,实现三百多倍的性能晋升。当数据量进一步增大,或是查问波及的表进一步增多时,汇集下推的性能晋升会更加显著。
无汇集下推 VS 有汇集下推比照
PieCloudDB 的全新优化器「达奇」为用户提供了一系列全面的逻辑优化性能,包含谓词下推、子查问子连贯晋升和外连贯打消等。作为一款面向在线剖析解决(OLAP)场景的数据库,优化器「达奇」不仅反对汇集下推性能,还具备 Data Skipping、预计算等高级个性,以满足各种简单查问的需要。在将来的文章中,咱们将逐个介绍这些性能,为您带来更深刻的理解。敬请关注!