【发布时间】:2017-01-16 14:31:01
【问题描述】:
我需要一些帮助来编写/优化查询以按类型检索每行的最新版本并根据类型执行一些计算。我认为最好用一个例子来说明。
给定以下数据集:
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| id | event_type | event_timestamp | message_id | sent_at | status | rate |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
| 1 | create | 2016-11-25 09:17:48 | 1 | 2016-11-25 09:17:48 | 0 | 0.500000 |
| 2 | status_update | 2016-11-25 09:24:38 | 1 | 2016-11-25 09:28:49 | 1 | 0.500000 |
| 3 | create | 2016-11-25 09:47:48 | 2 | 2016-11-25 09:47:48 | 0 | 0.500000 |
| 4 | status_update | 2016-11-25 09:54:38 | 2 | 2016-11-25 09:48:49 | 1 | 0.500000 |
| 5 | rate_update | 2016-11-25 09:55:07 | 2 | 2016-11-25 09:50:07 | 0 | 1.000000 |
| 6 | create | 2016-11-26 09:17:48 | 3 | 2016-11-26 09:17:48 | 0 | 0.500000 |
| 7 | create | 2016-11-27 09:17:48 | 4 | 2016-11-27 09:17:48 | 0 | 0.500000 |
| 8 | rate_update | 2016-11-27 09:55:07 | 4 | 2016-11-27 09:50:07 | 0 | 2.000000 |
| 9 | rate_update | 2016-11-27 09:55:07 | 2 | 2016-11-25 09:55:07 | 0 | 2.000000 |
+-------+-------------------+---------------------+-------------+---------------------+--------+----------+
预期的结果应该是:
+------------+--------------------+--------------------+-----------------------+
| sent_at | sum(submitted_msg) | sum(delivered_msg) | sum(rate_total) |
+------------+--------------------+--------------------+-----------------------+
| 2016-11-25 | 2 | 2 | 2.500000 |
| 2016-11-26 | 1 | 0 | 0.500000 |
| 2016-11-27 | 1 | 0 | 2.000000 |
+------------+--------------------+--------------------+-----------------------+
文章末尾是用于获取此结果的查询。我愿意打赌应该有一种优化它的方法,因为它使用带有连接的子查询,并且从我所读到的关于 BigQuery 的内容中,最好避免连接。但首先是一些背景:
本质上,数据集表示一个仅追加的表,其中写入了多个事件。数据规模以亿计,并将增长到数十亿+。由于 BigQuery 中的更新不实用,并且数据正在流式传输到 BQ,因此我需要一种方法来检索每个事件的最新事件,根据特定条件执行一些计算并返回准确的结果。查询是根据用户输入动态生成的,因此可以包含更多字段/计算,但为简单起见省略了。
- 只有一个
create事件,但n是任何其他类型的事件 - 对于每组事件,在计算时只应考虑最新的事件。
- status_update - 更新状态
- rate_update - 更新速率
- 创建 - 不言自明
- 每个不是
create的事件都可能不携带原始的其余信息/可能不准确(除了message_id和事件操作的字段)(数据集被简化,但想象一下还有很多列,以后会添加更多事件)- 例如
rate_update可能有也可能没有设置状态字段,或者不是最终值,因此无法对来自rate_update事件的状态字段进行计算,status_update也是如此
- 例如
- 可以假设表是按日期分区的,每个查询都会使用这些分区。为了简单起见,暂时省略了这些条件。
所以我想我有几个问题:
- 如何优化此查询?
- 将除
create之外的事件放在他们自己的表中是否更好,其中唯一可用的字段将是与事件相关的字段,以及连接所需的字段(message_id、event_timestamp)?这会减少处理的数据量吗? - 未来添加更多事件的最佳方式是什么,它们有自己的条件和计算方式?
实际上,任何有关如何高效且友好地查询此数据集的建议都非常受欢迎!谢谢! :)
我想出的怪物如下。 INNER JOINS 用于检索每一行的最新版本,根据这个resource
select
sent_at as sent_at,
sum(submitted_msg) as submitted,
sum(delivered_msg) as delivered,
sum(sales_rate_total) as sales_rate_total
FROM (
#DELIVERED
SELECT
d.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
0 as submitted_msg,
sum(if(status=1,1,0)) as delivered_msg,
0 as sales_rate_total
FROM `events` d
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type = "status_update"
group by 1
) g on d.message_id = g.message_id and d.event_timestamp = g.ts
GROUP BY 1,2
UNION ALL
#SALES RATE
SELECT
s.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
0 as submitted_msg,
0 as delivered_msg,
sum(sales_rate) as sales_rate_total
FROM `events` s
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type in ("rate_update", "create")
group by 1
) f on s.message_id = f.message_id and s.event_timestamp = f.ts
GROUP BY 1,2
UNION ALL
#SUBMITTED & REST
SELECT
r.message_id,
FORMAT_TIMESTAMP('%Y-%m-%d 00:00:00', sent_at) AS sent_at,
sum(if(status=0,1,0)) as submitted_msg,
0 as delivered_msg,
0 as sales_rate_total
FROM `events` r
INNER JOIN
(
select message_id, max(event_timestamp) as ts
from `events`
where event_type = "create"
group by 1
) e on r.message_id = e.message_id and r.event_timestamp = e.ts
GROUP BY 1, 2
) k
group by 1
【问题讨论】:
-
您可能也对类似的feature request感兴趣。
标签: sql performance google-bigquery query-optimization query-performance