IEJoin: 提高 Databend range join 性能

作者:王旭东

Databend 研发工程师

github.com/xudong963

IEJoin 算法可以高效的处理时序场景中的 Range(ASOF) Join。

Join conditions

Equi condition

在 下面 SQL 中

sql 复制代码
SELECT *
FROM employee JOIN department
ON employee.DepartmentID = department.DepartmentID AND 
employee.ID = department.ID;

employee.DepartmentID = department.DepartmentID OR employee.ID = department.ID 都是 equi-condition,它们用 AND 连接,这条 SQL 被称为 equi-join。

Non-equi condition

condition 可以是任意的 bool 表达式,不局限于 = 和 AND。这类 condition 被称为 non-equi condition, 进一步可以细分为 Range condition 和 Other condition。

  • Range condition

    • 范围比较,如 employee.DepartmentID > department.DepartmentID 就是 range condition, 这类 condition 在时序场景中非常常见。
  • Other condition

    • 除了 Range condition 的其他各种奇奇怪怪的 contition, 可以被归为 Other condition, 如 OR 连接的 condition, employee.DepartmentID = department.DepartmentID OR employee.ID = department.ID

Join condition → Join algorithm

在 Databend 中,我们根据 join condition 的类别选择不同的 join 算法,使 join 能够最高效。

如果包含 equi condition,选择 hash join (即使还包含其他类型的 condition ),hash join 可以高效的利用 equi condition 过滤到一定数量的数据,剩下的数据再利用其他 condition 过滤。

如果至少两个 IE condition,选择 IEJoin,一般数据库会使用 Nested Loop Joins,非常的低效。

如果只有一个 IE condition,选择 merge join。

什么是 IEJoin,它有什么黑魔法?

IEJoin

将 join keys 涉及到的 columns 放到 sorted arrays 中,利用 permutation array 来记录一个 sorted array 中 tuples 相对于另一个 sorted array 的位置,通过 bit array 来高效的计算符合两个 IE conditions 的 tuples 的交集。

IEJoin 在整体 pipeline 架构上的设计

IEJoin 算法

sql 复制代码
mysql> select * from east;
+------+------+------+-------+
| id   | dur  | rev  | cores |
+------+------+------+-------+
|  101 |  100 |   12 |     8 |
|  102 |   90 |    5 |     4 |
|  100 |  140 |   12 |     2 |
+------+------+------+-------+

mysql> select * from west;
+------+------+------+-------+
| t_id | time | cost | cores |
+------+------+------+-------+
|  404 |  100 |    6 |     4 |
|  498 |  140 |   11 |     2 |
|  676 |   80 |   10 |     1 |
|  742 |   90 |    5 |     4 |
+------+------+------+-------+
sql 复制代码
SELECT east.id, west.id
FROM east, west
WHERE east.dur < west.time AND east.rev > west.cost

这条 SQL 在大多数数据库中都会被按照 Cross join 处理(如果数据规模很大,甚至会直接 OOM ),但是如果用 IEjoin 算法来处理,速度会得到数量级的提升 🚀

为了便于理解,首先看一条 SelfJoin 的例子

sql 复制代码
SELECT s1.t_id, s2.t_id
FROM west s1, west s2
WHERE s1.time > s2.time AND s1.cost < s2.cost

time 列递增排序,得到 L1

cost 列递增排序,得到 L2

通过 L1 和 L2 可以得到 permutation array(P),P 记录了 L2 中 tuple id 在 L1 中位置

如:T4 在 L2 中的位置是1,对应到 L1 是2,所以 P 的第一个元素是 2。

初始化 bit-array,bit-array 是基于 L1 的,初始时全部为 0。

对于 L2,后 visit 的 cost 大于先 visit 的 cost,即满足 s1.cost < s2.cost,如先访问 T4,则 bit-array 的第二个元素被设置为 1,再访问 T3 的时候,对应 bit-array 中第一个元素,它后面的第二个元素已经被设置为 1,说明 T4.cost < T3.cost,则 {T4, T3} 符合条件 s1.cost < s2.cost

对于 L1,由于 bit-array 是基于 L1 的,所以如果 bit-array 中某个位置之后的位置被设置为 1,则表明后面设为 1 的位置的 tuple id 满足 s1.time > s2.time, 如 T1 对应的位置设为 1,当访问 T3 时,T1.time > T3.time,则 {T1, T3} 符合条件 s1.time > s2.time

bit-array 的作用就是通过标记,来找到同时满足两个 IE conditions 的 tuple pair。

算法流程

  • 遍历 P, P[1] 对应 T4,T4 在 L1 中的位置是 P[1] = 2,将 bit-array 的第二个位置设为 1,由于其后位置都为 0,所以没有满足条件的结果。

  • P[2] 对应 T1,T1 在 L1 中的位置是 P[1] = 3,将 bit-array 的第三个位置设为 1,由于其后位置都为 0,所以没有满足条件的结果。

  • P[3] 对应 T3,T3 在 L1 中的位置是 P[3] = 1,将 bit-array 的第一个位置设为1,由于 bit-array 的第二/三位置都为 1,所以 {T1, T3}, {T4, T3} 满足条件。

  • P[4] 对应 T2,T2 在 L1 中的位置是 P[4] = 4,将 bit-array 的第四个位置设为 1,由于它是最后一个位置,所以没有满足条件的结果。

由 SelfJoin 拓展到不同表 join

sql 复制代码
SELECT east.id, west.id
FROM east, west
WHERE east.dur < west.time AND east.rev > west.cost

对 dur 排序得到 L1,对 rev 排序得到 L2。 L2 和 L1 比较得到 P。

对 time 排序得到 L1',对 cost 排序得到 L2'。 L2' 和 L1' 比较得到 P'。

将 L1 和 L1' 合并排序,L2 和 L2' 合并排序,合并 P 和 P'。

最终得到了合 SelfJoin 类似的数据结构,可以应用 SelfJoin 的算法流程,但是需要处理掉重复的结果。

性能数据

M1 mac (10 core, 32G)

SQL: select count() from lineitem join orders on l_orderkey > o_orderkey and l_partkey < o_custkey;

TPCH SF 0.01

IEJoin: 0.974s, Cross join: 16.639s

TPCH SF 0.1

IEJoin: 79.085s, Cross join: OOM

Connect With Us

Databend 是一款开源、弹性、低成本,基于对象存储也可以做实时分析的新式数仓。期待您的关注,一起探索云原生数仓解决方案,打造新一代开源 Data Cloud。

相关推荐
xcLeigh1 分钟前
Python 项目实战:用 Flask 实现 MySQL 数据库增删改查 API
数据库·python·mysql·flask·教程·python3
威迪斯特2 分钟前
Flask:轻量级Web框架的技术本质与工程实践
前端·数据库·后端·python·flask·开发框架·核心架构
xu_yule4 分钟前
Redis存储(15)Redis的应用_分布式锁_Lua脚本/Redlock算法
数据库·redis·分布式
一灰灰blog20 分钟前
Spring AI中的多轮对话艺术:让大模型主动提问获取明确需求
数据库·人工智能·spring
Nandeska1 小时前
15、基于MySQL的组复制
数据库·mysql
AllData公司负责人2 小时前
AllData数据中台-数据同步平台【Seatunnel-Web】整库同步MySQL同步Doris能力演示
大数据·数据库·mysql·开源
加油,小猿猿2 小时前
Java开发日志-双数据库事务问题
java·开发语言·数据库
山岚的运维笔记2 小时前
SQL Server笔记 -- 第20章:TRY/CATCH
java·数据库·笔记·sql·microsoft·sqlserver
Gain_chance2 小时前
33-学习笔记尚硅谷数仓搭建-DWS层交易域用户粒度订单表分析及设计代码
数据库·数据仓库·hive·笔记·学习·datagrip
未来之窗软件服务3 小时前
计算机等级考试—高频英语词汇—东方仙盟练气期
数据库·计算机软考·东方仙盟