使用 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 表进行分区

旧版 sql 和标准 sql 之间的 BigQuery 表分区差异

有没有办法在 BigQuery 表上创建自定义日分区?

从 SQL 查询向 BigQuery 表添加多个分区列

Bigquery 集群不会降低查询成本