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

问题描述

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

event_id 事件类型 开始时间 结束时间
E1 TypeA T1 T4
E2 B 型 T2 T6
M1 TypeM T2 T6
E3 TypeA T3 T7
E4 B 型 T4 T7
E5 TypeA T5 T8
M2 TypeM T5 T8
E6 B 型 T6 T9
E7 TypeA T7 T10
E8 B 型 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',('E3',3,7),('E4',4,('E5',5,8),('M2',('E6',6,9),('E7',7,10),('E8',8,11),('M3',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 事件类型 开始时间 结束时间 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 个镶木地板文件要扫描这 10m 行。不要认为 S3 读取延迟会导致这里出现问题。

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

解决方法

提高性能:

  • 请注意,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 将其连接成一个字符串。