【问题标题】:How to choose the latest partition of a bigquery table in DBT without scanning the whole table?DBT中如何在不扫描整个表的情况下选择bigquery表的最新分区?
【发布时间】:2021-05-22 10:05:49
【问题描述】:

我正在尝试从 BigQuery 表中选择最新的分区,而不是在 DBT 模型中扫描整个表,以节省查询成本。

DBT 不允许在数据模型中使用分号,因此使用 DECLARE+SET 脚本语句不能像建议的 here 那样工作。

DBT 有一个 sql_header 宏,它允许在标头中设置一些变量,但该标头不接受对数据模型的引用,或者至少以下代码未编译:

{{ config(
  sql_header="  DECLARE latest_partition_date DATE;
  DECLARE latest_load_timestamp TIMESTAMP;
  SET latest_partition_date = (SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} );
  SET latest_load_timestamp = (SELECT MAX(loaded_at) FROM {{ ref("model") }} WHERE _PARTITIONDATE = latest_partition_date);"
) }}

-- set the main query
SELECT * FROM {{ ref("model") }}
WHERE 
-- Select the latest partition to reduce 'Bytes processed' for loading the query.
_PARTITIONDATE = latest_partition_date
-- Select the latest load within the latest partition to get only one duplicate of data.
AND loaded_at = latest_load_timestamp

我需要在标准 SQL 中解决这个问题。

建议的其他方法包括设置WHERE _PARTITIONDATE = CURRENT_DATE() 或使用DATE_SUB(CURRENT_DATE(), 3),但这些方法不能满足要求,因为数据加载中断是不可预测的,并且只能动态选择最新的方法。这可能吗?

【问题讨论】:

    标签: sql google-bigquery dbt


    【解决方案1】:

    您可以在另一个查询中执行此操作并将结果作为变量获取,如下所示:

        {%- call statement('max_partition', fetch_result=True) -%}
          SELECT MAX(_PARTITIONDATE) FROM {{ ref("model") }} )
        {%- endcall -%}
    
        {%- set max_date = load_result('max_partition')['data'][0][0] -%}
    
        SELECT * FROM {{ ref("model") }}
        WHERE 
        _PARTITIONDATE = {{ max_date }}
    

    【讨论】:

    • 当我运行它时,我收到错误消息:No matching signature for operator = for argument types: DATE, INT64. Supported signature: ANY = ANY。这可能是因为_PARTITIONDATEDATE 类型,但它似乎被评估为和INT。知道如何解决这个问题吗?
    • 那么您可能需要对其进行强制转换以检索该值,SELECT CAST(DATE(MAX(_PARTITIONDATE)) AS STRING) FROM {{ ref("model") }} 可能会用于检索它,也许您需要再次对其进行强制转换以在主查询中使用它。我有一个使用Timestamp 列的类似示例,但我没有尝试使用_PARTITIONDATE
    • 我尝试了强制转换,但在编译时 bgiquery 只是忽略了这一点,仍然继续强制变量为整数。我得到的解决方案需要在 jinja 中进行转换
    【解决方案2】:

    由于最初的问题是处理日期,因此缺少正确的数据类型转换。

    最后,我认为需要在 jinja 中完成对正确数据类型的转换,而不是使用 SQL 来让查询接受正确的变量。另外,{{ max_date }} 需要引号。

    我得到的最终解决方案是这样的:

    
    {%- call statement('max_partition_date_query', True) -%}
      SELECT MAX(_PARTITIONDATE) as max_partition_date FROM {{ ref('model') }}
    {%- endcall -%}
    
    {%- set max_timestamp = load_result('max_partition_date_query')['data'][0][0] -%}
    {%- set max_date = max_timestamp.strftime('%Y-%m-%d') -%}
    
    select * FROM {{ ref('model') }}
    WHERE _PARTITIONDATE = '{{ max_date }}'
    

    【讨论】:

      猜你喜欢
      • 2017-02-05
      • 2016-05-09
      • 2019-12-16
      • 2022-10-17
      • 1970-01-01
      • 1970-01-01
      • 2018-03-30
      • 2017-07-10
      • 2022-10-15
      相关资源
      最近更新 更多