You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让含ARRAY_AGG的BigQuery视图利用日期分区特性?

解决方案:让BigQuery含ARRAY_AGG的视图支持分区扫描

问题根源

当你用ARRAY_AGG(t ORDER BY updatedTime DESC LIMIT 1)[OFFSET(0)]按ID全局分组时,BigQuery优化器无法确定某个ID的最新记录是否仅存在于你过滤的createDt分区中,因此会默认扫描全表来确保找到每个ID的全局最新记录。而普通视图因为没有跨分区的分组逻辑,过滤条件可以直接下推到基表的分区扫描。

针对性解决方案

1. 用窗口函数改写(适用于仅需分区内最新记录的场景)

如果你的业务逻辑是只获取指定createDt分区内每个ID的最新记录(不关心该ID在其他分区的历史数据),可以用窗口函数替代ARRAY_AGG,让过滤条件能被优化器下推:

CREATE OR REPLACE VIEW my_dataset.my_view AS
SELECT * EXCEPT(rn)
FROM (
  SELECT 
    *,
    ROW_NUMBER() OVER(PARTITION BY ID ORDER BY updatedTime DESC) AS rn
  FROM my_dataset.base_table
)
WHERE rn = 1

查询视图时添加分区过滤:

SELECT * FROM my_dataset.my_view WHERE createDt = '2024-05-20'

此时BigQuery会先扫描createDt='2024-05-20'的分区,再在该分区内计算每个ID的最新记录,不会扫描全表。

2. 先过滤分区再聚合(适用于需全局最新但限定时间范围的场景)

如果你需要全局最新记录,但查询时仅关心某个时间范围内的ID,可以在查询时先过滤基表分区,再执行聚合:

SELECT 
  ARRAY_AGG(t ORDER BY updatedTime DESC LIMIT 1)[OFFSET(0)].*
FROM my_dataset.base_table t
WHERE createDt BETWEEN '2024-05-14' AND '2024-05-20'
GROUP BY ID

如果要封装成可复用的视图,可创建参数化视图:

CREATE OR REPLACE VIEW my_dataset.my_param_view(createDt_start, createDt_end) AS
SELECT 
  ARRAY_AGG(t ORDER BY updatedTime DESC LIMIT 1)[OFFSET(0)].*
FROM my_dataset.base_table t
WHERE createDt >= createDt_start AND createDt <= createDt_end
GROUP BY ID

查询时传入时间参数:

SELECT * FROM my_dataset.my_param_view('2024-05-14', '2024-05-20')

这种写法会强制先扫描指定分区范围,再执行聚合逻辑。

3. 用具体化视图(适用于数据更新频率低的场景)

如果你的基表数据更新不频繁,可以创建按createDt分区的具体化视图,预先完成聚合计算:

CREATE OR REPLACE MATERIALIZED VIEW my_dataset.my_mv
PARTITION BY createDt
AS
SELECT 
  ID,
  ARRAY_AGG(t ORDER BY updatedTime DESC LIMIT 1)[OFFSET(0)].* EXCEPT(ID)
FROM my_dataset.base_table t
GROUP BY ID, createDt

查询时直接过滤createDt即可扫描对应分区,且具体化视图会自动同步基表更新(有轻微延迟),查询性能更优。注意:此方案是按「分区+ID」聚合,若需全局ID的最新记录,不适用该方法。

内容的提问来源于stack exchange,提问作者Harikrishnan Balachandran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 13:11:13