在 Presto 中进行基于范围的交叉连接的最佳方法是啥?

Posted

技术标签:

【中文标题】在 Presto 中进行基于范围的交叉连接的最佳方法是啥?【英文标题】:What is the best way to do range based cross join in Presto?在 Presto 中进行基于范围的交叉连接的最佳方法是什么? 【发布时间】:2021-08-03 14:59:05 【问题描述】:

我在 Athena 中有一个表 event_log,其中包含从事件处理系统收集的日志。系统中有多个阶段,每个阶段按顺序处理这些事件。 start_time 列表示事件进入系统的时间,end_time 是它退出的时间。该系统每天处理数百万个事件。而且,我们在下表中有一年的数据。

event_id event_type start_time end_time
E1 TypeA T1 T4
E2 TypeB T2 T6
M1 TypeM T2 T6
E3 TypeA T3 T7
E4 TypeB T4 T7
E5 TypeA T5 T8
M2 TypeM T5 T8
E6 TypeB T6 T9
E7 TypeA T7 T10
E8 TypeB T8 T11
M3 TypeM T8 T11

有特殊类型的事件TypeM(标记事件)。我必须从这些日志中计算出这些特殊事件的处理延迟。根据上表,这可以通过过滤该类型的事件并将延迟计算为end_time - start_time 来实现。除此之外,我想通过额外的信息来增加延迟 - 处理此事件时在系统的各个阶段正在积极处理的事件数量。

-- sample event_log table
CREATE TABLE event_log AS 
SELECT * FROM ( 
    VALUES 
        ('E1','TypeA', 1, 4),  
        ('E2','TypeB', 2, 6),  
        ('M1','TypeM', 2, 6),  
        ('E3','TypeA', 3, 7),  
        ('E4','TypeB', 4, 7),  
        ('E5','TypeA', 5, 8),  
        ('M2','TypeM', 5, 8),  
        ('E6','TypeB', 6, 9),  
        ('E7','TypeA', 7, 10),  
        ('E8','TypeB', 8, 11),  
        ('M3','TypeM', 8, 11)  
) AS t (event_id, event_type, start_time, end_time) 

-- filtered marker table
CREATE TABLE marker_table AS
SELECT * FROM event_log
    WHERE event_type = 'TypeM'

-- Join with the filtered marker table on markers start and end time
SELECT mark.*,count(processed_events_in_band.event_id) AS events_processed_count
    FROM event_log processed_events_in_band
    JOIN marker_table mark
        ON processed_events_in_band.end_time between mark.start_time AND mark.end_time
    WHERE processed_events_in_band.event_type != 'TypeM'
    GROUP BY  mark.event_id 

预期结果

event_id event_type start_time end_time events_processed_count
M1 TypeM T2 T6 2 E1, E2
M2 TypeM T5 T8 4 E2, E3, E4, E5
M3 TypeM T8 T11 4 E5, E6, E7, E8

end_time 上有分区(每天)。一直在使用它们来减少数据扫描。单日数据最长可达10m。查询应该扩展到那个。查询具有 18K 行的标记表和具有 10m 行的事件日志大约需要 17 分钟。大约有 2K parquet 文件要扫描这 10m 行。不要认为 S3 读取延迟会导致这里出现问题。

如何优化此查询?有效获取这些数据的最佳方法是什么?

【问题讨论】:

是关于提高查询性能的问题,意思是减少 17 分钟的运行时间吗? 是的,它是关于提高性能并以正确的方式做到这一点。 【参考方案1】:

为了提高性能:

注意CREATE TABLE 会将查询的输出写入磁盘(doc)。考虑改用公用表表达式:
with marker_table as (SELECT * FROM event_log
    WHERE event_type = 'TypeM')
select ...
尝试在联接中使用带有= 符号的条件。 Presto 将执行效率更高的哈希连接。在您的情况下,我会尝试截断开始时间并截断结束时间,并使用截断时间相等(向上或向下)编写ON 条件 始终将最大的表放在连接的左侧 (doc) 如果您想添加正在处理的事件列表,而不仅仅是计数,您可以使用array_agg 函数 (doc) 结合array_distinct 生成唯一条目列表和array_join将其连接成一个字符串。

【讨论】:

我使用CREATE TABLE 只是为了演示。我主要对优化连接查询感兴趣。 它的 SELECT 查询大约需要 17 分钟。我正在遵循最佳实践,例如左侧更大的表、分区等。而且,不热衷于实际事件,计数应该做。即使是计数的近似值也应该足够好。 有什么方法可以在这里利用window functions 吗?我不确定在这里使用什么范围。

以上是关于在 Presto 中进行基于范围的交叉连接的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Presto 中交叉加入取消嵌套 JSON 数组

通过 PRESTO 连接器选择随机数据样本

Presto 多表连接和广播连接分布

基于ranger的presto账号权限管理及事件监听方案

在熊猫中按范围加入/合并的最佳方式

使用 Athena / Presto 从多个表返回 SQL 数据,受 1 个表中的日期范围限制