【问题标题】:How to choose the latest partition in BigQuery table?如何选择 BigQuery 表中的最新分区?
【发布时间】:2017-02-05 15:02:00
【问题描述】:

我正在尝试从按日期分区的 BigQuery 表中的最新分区中选择数据,但查询仍会从整个表中读取数据。

我试过了(据我所知,BigQuery 不支持QUALIFY):

SELECT col FROM table WHERE _PARTITIONTIME = (
  SELECT pt FROM (
    SELECT pt, RANK() OVER(ORDER by pt DESC) as rnk FROM (
      SELECT _PARTITIONTIME AS pt FROM table GROUP BY 1)
    )
  )
  WHERE rnk = 1
);

但这不起作用并读取所有行。

SELECT col from table WHERE _PARTITIONTIME = TIMESTAMP('YYYY-MM-DD')

'YYYY-MM-DD' 是一个特定的日期确实有效。

但是,我以后需要运行这个脚本,但是表更新(和_PARTITIONTIME)是不规则的。有没有办法只从 BigQuery 的最新分区中提取数据?

【问题讨论】:

  • 你能澄清一下 - 它是如何不起作用的吗?它有什么问题?
  • 我在下面评论过,但是这两个查询都不是从最新的分区中读取的。当我明确键入最后一个 _partitiontime 时,查询读取 18 MB。但是,当我尝试以下两个查询中的任何一个时,它们显示为 15.4 GB。
  • 我现在明白了。谢谢你的更新!有趣的是理解为什么。 @felipe-hoffa 提到了一些关于缓存的事情——但这并不清楚
  • 是的。这样它就可以工作,但有趣的是为什么它不能内联工作 - 在一个查询中
  • 我想我现在明白了。很明显,但这是我的猜测......所以当使用 value 时 - 涉及分区 get 并且 bq 引擎知道要扫描什么,不扫描什么;但是当使用表达式时 - 它的工作方式完全不同 - 分区本身并没有真正起作用(我认为这就是 Felipe 所说的缓存)所以在这种情况下查询被视为连接,因此整个表被扫描并连接到表达式的结果。仍然可以通过编写该逻辑脚本来轻松解决 - 正如您所提到的 - 首先获取子查询的结果,然后在最终查询中使用它

标签: google-bigquery


【解决方案1】:

2019 年 10 月更新

ScriptingStored Procedures 的支持现在处于测试阶段(截至 2019 年 10 月)

您可以提交多个用分号分隔的语句,BigQuery 现在可以运行它们

见下例

DECLARE max_date TIMESTAMP;
SET max_date = (
  SELECT MAX(_PARTITIONTIME) FROM project.dataset.partitioned_table`);

SELECT * FROM `project.dataset.partitioned_table`
WHERE _PARTITIONTIME = max_date;

为那些喜欢在不检查上下文等的情况下投票的人更新。

我认为,这个答案被接受了,因为它解决了 OP 的主要问题Is there a way I can pull data only from the latest partition in BigQuery?,并且在 cmets 中提到,很明显 BQ 引擎仍然扫描所有行,但仅根据最近的分区返回结果。正如评论中已经提到的那样 - Still something that easily to be addressed by having that logic scripted - first getting result of subquery and then use it in final query

试试

SELECT * FROM [dataset.partitioned_table]
WHERE _PARTITIONTIME IN (
  SELECT MAX(TIMESTAMP(partition_id))
  FROM [dataset.partitioned_table$__PARTITIONS_SUMMARY__]
)  

SELECT * FROM [dataset.partitioned_table]
WHERE _PARTITIONTIME IN (
  SELECT MAX(_PARTITIONTIME) 
  FROM [dataset.partitioned_table]
)  

【讨论】:

  • 请注意,这将停止查询结果缓存(可能会影响成本)。
  • 这个答案解决了Is there a way I can pull data only from the latest partition in BigQuery?的问题!很明显,引擎仍然扫描所有行,但仅根据最近的分区返回结果。正如评论中已经提到的那样 - Still something that easily to be addressed by having that logic scripted - first getting result of subquery and then use it in final query
  • 脚本方法在您手动浏览数据时非常有用,但在使用 api 客户端并将结果存储在目标表中时不起作用。在这些情况下,您仍然必须作为两个作业运行,第一个作业的输出用作第二个作业的输入,不幸的是:configuration.query.destinationTable cannot be set for scripts
  • @LarsHaugseth 您可以在脚本中使用 INSERT INTO 或 CREATE AND REPLACE 来解决无法设置目标表的问题
  • DECLARE 的坏处是你不能在视图中使用它
【解决方案2】:

很抱歉挖掘了这个老问题,但它出现在 Google 搜索中,我认为接受的答案具有误导性。

据我从documentation 和正在运行的测试中得知,接受的答案将修剪分区,因为子查询用于确定最近的分区:

需要对查询的多个阶段进行评估以解析谓词(例如内部查询或子查询)的复杂查询不会从查询中删除分区。

因此,尽管建议的答案会提供您期望的结果,但它仍会查询所有分区。它不会忽略所有旧分区,只查询最新的。

诀窍是使用或多或少的常数进行比较,而不是子查询。例如,如果_PARTITIONTIME 不是不规则的,而是每天的,请尝试通过获取昨天的分区来修剪分区,如下所示:

SELECT * FROM [dataset.partitioned_table]
    WHERE _PARTITIONDATE = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)

当然,这并不总是最新数据,但就我而言,这恰好足够接近。如果您想要今天的数据,请使用INTERVAL 0 DAY,并且不关心查询将在当天尚未创建分区的那部分返回 0 个结果。

我很高兴了解是否有更好的解决方法来获取最新的分区!

【讨论】:

    【解决方案3】:

    列出所有分区:

    #standardSQL
    SELECT
      _PARTITIONTIME as pt
    FROM
      `[DATASET].[TABLE]`
    GROUP BY 1
    

    然后选择最新的时间戳。

    祝你好运:)

    https://cloud.google.com/bigquery/docs/querying-partitioned-tables

    【讨论】:

    • 此查询在运行时处理 0 个字节
    【解决方案4】:

    我找到了解决此问题的方法。您可以使用 with 语句,选择最后几个分区并过滤掉结果。这是我认为更好的方法,因为:

    1. 您不受固定分区日期的限制(例如今天 - 1 天)。它将始终采用给定范围内的最新分区。
    2. 它只会扫描最后几个分区,而不是整个表。

    最近 3 个分区扫描的示例:

    WITH last_three_partitions as (select *, _PARTITIONTIME as PARTITIONTIME 
        FROM dataset.partitioned_table 
        WHERE  _PARTITIONTIME > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 3 DAY))
    SELECT col1, PARTITIONTIME from last_three_partitions 
    WHERE PARTITIONTIME = (SELECT max(PARTITIONTIME) from last_three_partitions)
    

    【讨论】:

    • 你的限制不是今天 - 1 而是今天 - 3,感觉就像是同样的限制。
    • 取决于您的用例。对我们来说,由于各种原因导致最后一天的分区不可用是很常见的,但我们总是有一些较旧的数据可用。因此 3 天就解决了我们的问题。
    【解决方案5】:

    您可以利用__TABLES__ 表列表来避免重新扫描所有内容或不得不希望最新分区是大约 3 天前。我做了splitordinal 的东西以防万一我的表前缀由于某种原因在表名中出现多次。

    这应该适用于_PARTITIONTIME_TABLE_SUFFIX

    select * from `project.dataset.tablePrefix*` 
    where _PARTITIONTIME = (
        SELECT split(table_id,'tablePrefix')[ordinal(2)] FROM `project.dataset.__TABLES__` 
        where table_id like 'tablePrefix%'
        order by table_id desc limit 1)
    

    【讨论】:

    【解决方案6】:

    一种折衷方案,即设法仅查询几个分区,而无需借助脚本或因丢失固定日期的分区而失败。

    WITH latest_partitions AS (
      SELECT *, _PARTITIONDATE AS date
      FROM `myproject.mydataset.mytable`
      WHERE _PARTITIONDATE > DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
    )
    SELECT
      *
    FROM
      latest_partitions
    WHERE
      date = (SELECT MAX(date) FROM latest_partitions)
    

    【讨论】:

      【解决方案7】:

      我在一个不太受欢迎的问题中得到了这个答案,所以在此处复制它是相关的(而且这个问题正在获得更多的综合浏览量):

      米哈伊尔的回答看起来像这样(处理公共数据):

      SELECT MAX(views)
      FROM `fh-bigquery.wikipedia_v3.pageviews_2019` 
      WHERE DATE(datehour) = DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)     
      AND wiki='es' 
      # 122.2 MB processed
      

      但问题似乎是这样的:

      SELECT MAX(views)
      FROM `fh-bigquery.wikipedia_v3.pageviews_2019` 
      WHERE DATE(datehour) = (SELECT DATE(MAX(datehour)) FROM `fh-bigquery.wikipedia_v3.pageviews_2019` WHERE wiki='es')     
      AND wiki='es'
      # 50.6 GB processed
      

      ...但小于 50.6GB

      您现在需要的是某种脚本,分两步执行:

      max_date = (SELECT DATE(MAX(datehour)) FROM `fh-bigquery.wikipedia_v3.pageviews_2019` WHERE wiki='es')   
      
      ;
      
      SELECT MAX(views)
      FROM `fh-bigquery.wikipedia_v3.pageviews_2019` 
      WHERE DATE(datehour) = {{max_date}}
      AND wiki='es'
      # 115.2 MB processed
      

      您必须在 BigQuery 之外编写此脚本 - 或在 https://issuetracker.google.com/issues/36955074 上等待消息。

      【讨论】:

        猜你喜欢
        • 2019-09-22
        • 2021-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多