最佳实践|Apache Doris Join 实现与调优实践

概述

Doris 支持两种物理算子,一类是 Hash Join,另一类是 Nest Loop Join

  • Hash Join:在右表上根据等值 Join 列建立哈希表,左表流式的利用哈希表进行 Join 计算,它的限制是只能适用于等值 Join。

  • Nest Loop Join:通过两个 for 循环,很直观。然后它适用的场景就是不等值的 Join,例如:大于小于或者是需要求笛卡尔积的场景。它是一个通用的 Join 算子,但是性能表现差。

图片

案例一:

看下面图上的 Profile ,一个四张表 Join 的查询,通过 Profile 的时候发现第二个 Join 耗时很高,耗时 14 秒。

进一步分析 Profile 之后,发现 BuildRows,就是右表的数据量是大概 2500 万。而 ProbeRows ( ProbeRows 是左表的数据量)只有 1 万多。这种场景下右表是远远大于左表,这显然是个不合理的情况。这显然说明 Join 的顺序出现了一些问题。这时候尝试改变 Session 变量,开启 Join Reorder。

set enable_cost_based_join_reorder = true

这次耗时从 14 秒降到了 4 秒,性能提升了 3 倍多。

此时再 Check Profile 的时候,左右表的顺序已经调整正确,即右表是大表,左表是小表。基于小表去构建哈希表,开销是很小的,这就是典型的一个利用 Join Reorder 去提升 Join 性能的一个场景。

图片

案例二:

第二个 Case,存在一个慢查询,查看 Profile 之后,整个 Join 节点耗时大概44秒。它的右表有 1000 万,左表有 6000 万,最终返回的结果也只有 6000 万。

这里可以大致的估算出过滤率是很高的,那为什么 Runtime Filter 没有生效呢?通过 Query Plan 去查看它,发现它只开启了 IN 的 Runtime Filter。

图片

前面介绍了,当右表超过1024行的话, IN 是不生效的,所以根本起不到什么过滤的效果,所以尝试调整 RuntimeFilter 的类型。

这里改为了 BloomFilter,左表的 6000 万条数据过滤了 5900 万条。基本上 99% 的数据都被过滤掉了,这个效果是很显著的。查询也从原来的 44 秒降到了 13 秒,性能提升了大概也是三倍多。

图片

案例三:

下面是一个比较极端的 Case,通过一些环境变量调优也没有办法解决,因为它涉及到 SQL Rewrite,所以这里列出来了原始的 SQL 。

这个 Join 查询是很简单的,单纯的一个左右表的 Join 。当然它上面有一些过滤条件,打开 Profile 的时候,发现整个查询 Hash Join 执行了三分多钟,它是一个 BroadCast 的 Join,它的右表有 2 亿条,左表只有 70 万。在这种情况下选择了 Broadcast Join 是不合理的,这相当于要把 2 亿条做一个 Hash Table,然后用 70 万条遍历两亿条的 Hash Table ,这显然是不合理的。

图片

为什么会产生不合理的 Join 顺序呢?其实这个左表是一个 10 亿条级别的大表,它上面加了两个过滤条件,加完这两个过滤条件之后, 10 亿条的数据就剩 70 万条了。但 Doris 目前没有一个好的统计信息收集的框架,所以它不知道这个过滤条件的过滤率到底怎么样。所以这个 Join 顺序安排的时候,就选择了错误的 Join 的左右表顺序,导致它的性能是极其低下的。

下图是改写完成之后的一个 SQL 语句,在 Join 后面添加了一个Join Hint,在Join 后面加一个方括号,然后把需要的 Join 方式写入。这里选择了 Shuffle Join,可以看到右边它实际查询计划里面看到这个数据确实是做了 Partition ,原先 3 分钟的耗时通过这样的改写完之后只剩下 7 秒,性能提升明显。

图片

接下来就根据今天分享的内容做一个 最佳实践原则总结。主要分为 4 点:

  • 第一点:在做 Join 的时候,要尽量选择同类型或者简单类型的列,同类型的话就减少它的数据 Cast,简单类型本身 Join 计算就很快。

  • 第二点:尽量选择 Key 列进行 Join, 原因前面在 Runtime Filter 的时候也介绍了,Key 列在延迟物化上能起到一个比较好的效果。

  • 第三点:大表之间的 Join ,尽量让它 Co-location ,因为大表之间的网络开销是很大的,如果需要去做 Shuffle 的话,代价是很高的。

  • 第四点:合理的使用 Runtime Filter,它在 Join 过滤率高的场景下效果是非常显著的。但是它并不是万灵药,而是有一定副作用的,所以需要根据具体的 SQL 的粒度做开关。

  • 最后:要涉及到多表 Join 的时候,需要去判断 Join 的合理性。尽量保证左表为大表,右表为小表,然后 Hash Join 会优于 Nest Loop Join。必要的时可以通过 SQL Rewrite,利用 Hint 去调整 Join 的顺序。

原文链接:最佳实践|Apache Doris Join 实现与调优实践

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache Doris(孵化器项目)是一个开源的分布式实时数据仓库,旨在提供高性能和可伸缩性的数据分析和报告能力。它的主要原理和实践如下: 1. 列式存储:Apache Doris使用列式存储来存储数据,即将每列的数据分开存储在不同的文件中。这种存储方式有助于提高数据的压缩率,减少存储空间的占用,并提高数据查询的效率。 2. 分布式架构:Apache Doris采用分布式架构,将数据分片存储在多个节点上,以实现数据的水平扩展和负载均衡。每个节点都有相同的数据副本,确保数据的高可靠性和容错性。 3. Write-optimized:Apache Doris采用了“write-optimized”(写优化)的设计理念,即将写入操作的性能优化至极致。它使用了基于LSM树(Log-structured Merge Tree)的数据结构,将写入操作顺序化和批处理,大大提高了写入性能。 4. 计算与存储分离:Apache Doris将计算和存储分离,通过多个计算引擎(如Palo,Spark)对数据进行分析和查询。这种架构允许根据需求进行灵活的扩缩容,并提供了多种数据接入和导出方式。 在实践中,可以按照以下步骤使用Apache Doris: 1. 安装和配置:首先需要下载和部署Apache Doris,然后进行相关配置,包括节点的IP地址、端口号、数据存储路径等。 2. 数据导入:将数据导入到Apache Doris中,可以通过多种方式,如使用ETL工具、使用JDBC驱动程序或通过API进行数据导入。 3. 数据模型设计:根据需求设计数据模型,包括表的结构、字段名和数据类型等。 4. 数据分片和分布:根据数据量和负载要求,将数据分片存储在不同的节点上,并确保数据的均衡分布。 5. 数据查询和分析:使用SQL语句对数据进行查询和分析,通过连接计算引擎对数据进行处理和计算,并根据需要生成相应的报表和图表。 6. 集群监控和管理:通过监控工具对集群进行实时监控,包括节点的状态、负载情况和性能指标等,及时发现和解决问题。 总之,Apache Doris通过列式存储、分布式架构、写优化和计算与存储分离等原理,提供了高效可靠的数据分析和报告能力。在实践中,可以根据需求进行安装配置、数据导入、数据模型设计、数据查询和分析,以及集群监控和管理等步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值