使用 bigquery 和单个查询进行分区,根据日期将表拆分为多个表
Posted
技术标签:
【中文标题】使用 bigquery 和单个查询进行分区,根据日期将表拆分为多个表【英文标题】:Split table into multiple tables based on date using bigquery with a single query for partitioning 【发布时间】:2017-02-03 18:51:55 【问题描述】:我想要做的原来的“为什么”是:
恢复一个保持其原始分区的表,而不是全部进入今天的分区。
我想我能做的就是bq load
到一个临时表。然后运行一个查询,按照bq partition
所需的命名约定,即sharded_YYYYMMDD
,每天将该表拆分为一个表YYYYMMDD。然后运行bq partition
。
此页面https://cloud.google.com/bigquery/docs/creating-partitioned-tables 提供了示例,但它需要每天运行一个查询。那可能是数百个:
bq query --use_legacy_sql=false --allow_large_results --replace \
--noflatten_results --destination_table 'mydataset.temps$20160101' \
'SELECT stn,temp from `bigquery-public-data.noaa_gsod.gsod2016` WHERE mo="01" AND da="01" limit 100'
那么我如何创建一个查询,该查询将遍历所有天并每天创建一个表?
我在这里Split a table into multiple tables in BigQuery SQL 发现了一个类似的问题,但没有关于使用单个查询的答案。
【问题讨论】:
【参考方案1】:这里的主要问题是每天都进行全面扫描。其余的问题不大,可以在任何client of your choice 中轻松编写脚本
那么,以下是 - 如何避免每天进行全表扫描?
请尝试以下逐步查看方法 它足够通用,可以扩展/适用于您的实际案例 - 同时我在您的问题中使用与您相同的示例,并且我将锻炼限制在 10 天
第 1 步 - 创建数据透视表 在这一步中,我们 a) 将每一行的内容压缩到记录/数组中 b) 将它们全部放入各自的“每日”列中
#standardSQL
SELECT
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160101' THEN r END) AS day20160101,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160102' THEN r END) AS day20160102,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160103' THEN r END) AS day20160103,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160104' THEN r END) AS day20160104,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160105' THEN r END) AS day20160105,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160106' THEN r END) AS day20160106,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160107' THEN r END) AS day20160107,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160108' THEN r END) AS day20160108,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160109' THEN r END) AS day20160109,
ARRAY_CONCAT_AGG(CASE WHEN d = 'day20160110' THEN r END) AS day20160110
FROM (
SELECT d, r, ROW_NUMBER() OVER(PARTITION BY d) AS line
FROM (
SELECT
stn, CONCAT('day', year, mo, da) AS d, ARRAY_AGG(t) AS r
FROM `bigquery-public-data.noaa_gsod.gsod2016` AS t
GROUP BY stn, d
)
)
GROUP BY line
在 Web UI 中使用 pivot_table(您可以在此处选择所需的任何名称)作为目标运行上述查询
如您所见 - 在这里我们将获得 10 列的表 - 一天一列,每列的架构是原始表架构的副本:
第 2 步 – 一个一个地创建分片表,只扫描相应的列(没有全表扫描)
#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20160101) AS r
使用名为 mytable_20160101 的目标表从 Web UI 运行上述查询
你可以在第二天继续运行
#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20160102) AS r
现在您应该有名为 mytable_20160102 的目标表,依此类推 您应该能够使用您选择的任何客户端自动化/编写此步骤 注意:那些最终的每日表格将具有与原始表格完全相同的架构!
您可以如何使用上述方法有很多变体 - 这取决于您的创造力
注意:BigQuery 最多允许表中包含 10000 列,因此一年中的相应天数为 365 列绝对不是问题 :o)
【讨论】:
【参考方案2】:在这里回答自己。我见过的另一种方法是编写一个脚本:
解析tablebackup.json
文件,输出多个文件tablebackuppartitionYYYYMMDD.json
在提供的参数上拆分。
创建一个批处理脚本,将bq load
的所有文件放到相应的表分区中。
脚本需要逐行或逐块处理才能处理大量备份。并且需要一些时间。使用这种方法的优点是它是通用的并且可供未经培训的 BQ 系统管理员使用。
【讨论】:
以上是关于使用 bigquery 和单个查询进行分区,根据日期将表拆分为多个表的主要内容,如果未能解决你的问题,请参考以下文章
在 bigquery 中使用标准 sql 查询缓冲区/未分区数据
在 python 中通过 API 对 BigQuery 表进行分区