在 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 中进行基于范围的交叉连接的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章