300 倍的性能提升!PieCloudDB Database 优化器「达奇」又出新“招”啦
随着数字化进程的加快,全球数据量呈指数级增长,对数据库系统的性能提出了巨大的挑战。优化器作为数据库管理系统中的关键技术,对数据库性能和效率具有重要影响,它通过对用户的查询请求进行解析和优化来生成高效的执行计划,进而快速返回查询结果。然而,同一条 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、预计算等高级特性,以满足各种复杂查询的需求。在未来的文章中,我们将逐一介绍这些功能,为您带来更深入的了解。敬请关注!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
分库分表之拆分键设计 | 京东物流技术团队
众所周知,在现实世界中,每一个资源都有其提供能力的最大上限,当单一资源达到最大上限后就得让多个资源同时提供其能力来满足使用方的需求。同理,在计算机世界中,单一数据库资源不能满足使用需求时,我们也会考虑使用多个数据库同时提供服务来满足需求。当使用了多个数据库来提供服务时,最为关键的点是如何让每一个数据库比较均匀的承担压力,而不至于其中的某些数据库压力过大,某些数据库没什么压力。这其中的关键点之一就是拆分键的设计。 1 水平、垂直拆分 在关系数据库中,当单个库的负载、连接数、并发数等达到数据库的最大上限时,就得考虑做数据库和表的拆分。如一个简单的电商数据库,在业务初期,为了快速验证业务模式,把用户、商品、订单都放到一个数据库中,随着业务的发展及用户量的增长,单数据库逐渐不能支撑业务(MySQL中单记录容量超过1K时,单表数据量建议不超过一千万条),这时就得考虑把数据库和表做出拆分。 1.1 垂直拆分 简单的说就是将数据库及表由一个拆分为多个,如我们这里的电商数据库,可以垂直拆分为用户数据库、商品数据库和订单数据库,订单表可以垂直拆分为订单基本信息表,订单收货地址表、订单商品表等,每一个表里...
- 下一篇
Databend 开源周报第 107 期
Databend 是一款现代云数仓。专为弹性和高效设计,为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务:https://app.databend.cn 。 What's On In Databend 探索 Databend 本周新进展,遇到更贴近你心意的 Databend 。 理解连接参数 连接参数 是建立与 Databend 支持的外部存储服务(如Amazon S3)的连接时所需的一组身份验证和配置信息。这些参数被括号包围、由一组用逗号或空格分隔的键值对组成。在创建 Stage 、COPY INTO 和查询外部文件时都会用到。 下面的 SQL 语句展示了如何利用连接参数创建用 S3 作为底层存储的 Stage 。 CREATE STAGE my_s3_stage URL = 's3://load/files/' CONNECTION = ( ACCESS_KEY_ID = '<your-access-key-id>', SECRET_ACCESS_KEY = '<your-secret-access-key>' ); 如果您想了解更多信息,请查看下面...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS关闭SELinux安全模块
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7安装Docker,走上虚拟化容器引擎之路