繁体   English   中英

如何在不扫描整个表的情况下选择 DBT 中 bigquery 表的最新分区?

[英]How to choose the latest partition of a bigquery table in DBT without scanning the whole table?

我正在尝试 select 来自 BigQuery 表的最新分区,而不扫描 DBT model 中的整个表以节省查询成本。

DBT 不允许在数据 model 中使用分号,因此使用DECLARE + SET脚本语句不能按照此处的建议工作。

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

{{ 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)但这些方法不能满足要求,因为数据加载中断是不可预测的,只有动态选择最新的才能在这里工作。 那可能吗?

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

    {%- 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 }}

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

最后,我认为需要在 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 }}'

上述方法适用于https://cloud.google.com/bigquery/docs/partitioned-tables#ingestion_time但不适用于https://cloud.google.com/bigquery/docs/partitioned-tables#date_timestamp_partitioned_table

另一种选择是利用https://cloud.google.com/bigquery/docs/information-schema-tables获取日期/时间戳分区表的最新分区。

{% set last_snapshot_at_query %}
SELECT 
    PARSE_TIMESTAMP("%Y%m%d", MAX(PARTITION_ID)) 
FROM
    {{ source("change-me-source", "INFORMATION_SCHEMA.PARTITIONS") }} 
WHERE
    table_name = "change-me-table"
{% endset %}

{% if execute %}
{% set last_snapshot_at = run_query(last_snapshot_at_query).columns[0][0] %}
{% endif %}

SELECT
    *
FROM
    {{ source('change-me-source', 'change-me-table') }},
WHERE 
    snapshot_at = "{{ last_snapshot_at }}"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM