使用 Google BigQuery 上的开始/结束日期优化活动帐户查询
Posted
技术标签:
【中文标题】使用 Google BigQuery 上的开始/结束日期优化活动帐户查询【英文标题】:Optimize Active Accounts Query with Start / End Date on Google BigQuery 【发布时间】:2018-03-16 20:13:10 【问题描述】:我希望优化查询以获取每个间隔(天、周等)的活动帐户,其中活动是在帐户的开始和结束日期定义的。布局如下:
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
我还每天使用一个子选择,在 6 到 9 个月前,当 BigQuery 仍然具有性能等级并且在 CPU 方面有更多的余地时,它曾经在类似情况下表现得相当好。但现在似乎更严格/效率更低,因为他们取消了更高的计算层定价。此执行大约需要 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`
现在的问题是:有没有办法获得物化交叉连接的性能,而无需首先实际炸毁数据并将其物化,即实时而无需开销。
我正在尝试使用一些分析功能,但找不到可以做到这一点的东西。
【问题讨论】:
【参考方案1】:我认为您的第一个查询非常完美,并且是一种方法 它已经是最通用的,适用于任何时间间隔(天、周等),并且在所有非物化选项中都适用——最快的一个
唯一的潜在改进(而且更紧凑)如下(在我使用虚拟数据进行的快速测试中,它不断显示出稍微快一点的结果 - 但我不能肯定 - 看到你的结果会很有趣真实数据)
#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
【讨论】:
感谢您的反馈,您的版本稍好一些(~10%*),我仍然希望以某种方式获得更好的结果,我正在尝试通过分析功能完成它,但是还没有找到合适的组合。 *好奇地看到它的性能稍微好一点,我希望查询编译器将它翻译成同一个作业,如果我检查它实际具有的执行计划,因为它具有完全相同的阶段和行数/大小。 我玩了一点窗口/分析函数 - 但性能明显较慢 - 所以我放弃了针对您的具体情况的这个方向以上是关于使用 Google BigQuery 上的开始/结束日期优化活动帐户查询的主要内容,如果未能解决你的问题,请参考以下文章
BigQuery 上的提取作业不能确保 Google 存储上的文件