我正在尝试从日期分区的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的最新分区中提取数据?
答案 0 :(得分:4)
很抱歉,您想找到这个老问题,但它在Google搜索中出现,我认为公认的答案具有误导性。
据我从documentation进行的测试中得出的结论,接受的答案将不修剪分区,因为使用子查询来确定最新的分区:
需要解析查询的多个阶段才能解析谓词的复杂查询(例如内部查询或子查询),不会从查询中删除分区。
因此,尽管建议的答案将提供您期望的结果,但仍将查询所有分区。它将不忽略所有旧分区,仅查询最新分区。
诀窍是使用或多或少的常量进行比较,而不是使用子查询。例如,如果_PARTITIONTIME
并非每天都有规律,请尝试通过获取昨天的分区来修剪分区,如下所示:
SELECT * FROM [dataset.partitioned_table]
WHERE _PARTITIONDATE = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
当然,这并不总是最新的数据,但就我而言,这恰好足够接近。如果您需要今天的数据,请使用INTERVAL 0 DAY
,并且不在乎该查询在一天中尚未创建分区的那一天的一部分将返回0结果。
很高兴得知是否有更好的解决方法来获取最新的分区!
答案 1 :(得分:1)
列出所有分区:
#standardSQL
SELECT
_PARTITIONTIME as pt
FROM
`[DATASET].[TABLE]`
GROUP BY 1
然后选择最新的时间戳。
祝你好运:)https://cloud.google.com/bigquery/docs/querying-partitioned-tables
答案 2 :(得分:1)
一种折衷方案,可以仅查询几个分区,而不必求助于脚本编写或在固定日期丢失分区而失败。
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)
答案 3 :(得分:0)
更新那些喜欢downvoting而不检查上下文等的人。
我认为,这个答案之所以被接受是因为它解决了OP的主要问题Is there a way I can pull data only from the latest partition in BigQuery?
,并且在评论中提到很明显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]
)
答案 4 :(得分:0)
我找到了解决此问题的方法。您可以使用with语句,选择最后几个分区并过滤出结果。我认为这是更好的方法,因为:
最近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)
答案 5 :(得分:0)
您可以利用表的__TABLES__
列表来避免重新扫描所有内容,或者不必希望最新分区在3天之前。我做了split
和ordinal
的工作,以防我的表前缀由于某种原因在表名中多次出现。
这应该适用于_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 :(得分:0)
我在一个不太受欢迎的问题中得到了这个答案,因此将其复制到相关的位置(此问题将获得更多的浏览量):
Mikhail的答案看起来像这样(处理公共数据):
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
现在您需要某种脚本,以2个步骤执行此操作:
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上的新闻。