我希望优化查询以获得每个时间间隔(日,周等)的活动帐户,其中活动在帐户的开始日期和结束日期定义。布局如下:
accounts:
account_id Int
subscription_start Timestamp
subscription_end Timestamp -- null if still active
我尝试了几种方法,最快的方法是使用generate_array动态创建数组,然后取消它们(约2分钟)
with nested_dates as (
select GENERATE_DATE_ARRAY(DATE(subscription_start), IFNULL(date(subscription_end), current_date()), INTERVAL 1 DAY) as dates
from `accounts`
),
all_dates as (
select date_item from nested_dates, UNNEST(dates) as date_item
)
select date_item, count(1) from all_dates group by date_item
我还使用了每天一个subselect,它曾经在6-9个月之前的类似情况下表现相当不错,当时BigQuery仍然拥有性能层,并且给了CPU更多的lee方式。但现在它们似乎更加严格/效率更低,因为它们取消了更高的计算层价格。这个执行大约需要12分钟。
select
day,
(select
count(1)
from `accounts` where
subscription_start <= day and
(subscription_end is null or subscription_end >= day)
)
from unnest(
generate_date_array(date('2015-06-01'), current_date(), interval 1 day)
) AS day
我还对生成日期和条件总和的帐户交叉连接进行了性能测试(由于超出CPU限制,在3300秒后失败)。
当我为每个已激活的帐户生成一个包含所有日期的物化表时,当然我的实施分区可能更快(例如,通过使用来自第一个查询的“all_dates”。
select date(day_active), count(1) from `account_all_dates`
现在的问题是:有没有办法获得物化交叉连接的性能而不先实际耗尽数据并实现它,即实时没有开销。
我正在尝试一些分析功能,但找不到可以做到这一点的东西。
答案 0 :(得分:4)
我认为您的第一个查询是完美的,是一种方法 它已经是最通用的,适用于任何间隔(日,周等)和所有非物化选项 - 最快的
唯一可能的改进(也有点更紧凑)在下面(在我使用虚拟数据的快速测试中,它总是显示稍快的结果 - 但我不能说这是肯定的 - 看到你的结果会很有趣真实数据)
#standardSQL
SELECT date_item, COUNT(1) active_accounts
FROM `accounts`,
UNNEST(GENERATE_DATE_ARRAY(DATE(subscription_start),
IFNULL(DATE(subscription_end), CURRENT_DATE()), INTERVAL 1 DAY)) date_item
GROUP BY date_item