从非分区表迁移到分区表

时间:2016-08-17 10:18:37

标签: google-bigquery

6月,BQ团队announced support for date-partitioned tables。但是指南缺少如何将旧的非分区表迁移到新样式中。

我正在寻找一种方法来将几个或者不是所有的表更新为新样式。

在DAY类型之外还划分了其他可用选项吗? BQ UI是否显示了这一点,因为我无法从BQ Web UI创建这样一个新的分区表。

5 个答案:

答案 0 :(得分:14)

  

来自Pavan的回答:请注意,这种方法会向您收取查询源表的扫描成本。查询次数。
  

<小时/>   来自Pentium10评论:所以假设我有几年的数据,我需要为每天准备不同的查询并运行所有这些,并假设我有1000天的历史,我需要支付1000倍的完整查询价格来自源表?

我们可以看到 - 这里的主要问题是每天都要进行全面扫描。剩下的不是问题,可以在任何client of the choice

中轻松编写脚本

所以,下面是 - 如何分区表,同时避免每天都进行全表扫描?

下面逐步介绍方法

通用性足以扩展/适用于任何真实用例 - 同时我使用bigquery-public-data.noaa_gsod.gsod2017并且我将“运动”限制为仅仅10天以保持其可读性

第1步 - 创建数据透视表
在这一步中我们 a)将每行的内容压缩成记录/数组

b)将它们全部放入各自的“每日”栏目

  
#standardSQL
SELECT
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170101' THEN r END) AS day20170101,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170102' THEN r END) AS day20170102,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170103' THEN r END) AS day20170103,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170104' THEN r END) AS day20170104,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170105' THEN r END) AS day20170105,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170106' THEN r END) AS day20170106,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170107' THEN r END) AS day20170107,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170108' THEN r END) AS day20170108,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170109' THEN r END) AS day20170109,
  ARRAY_CONCAT_AGG(CASE WHEN d = 'day20170110' THEN r END) AS day20170110
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.gsod2017` AS t 
    GROUP BY stn, d
  ) 
)
GROUP BY line  

使用pivot_table(或任何名称首选)在Web UI中运行上述查询作为目标

正如我们所看到的 - 这里我们将获得包含10列的表 - 一天有一列,每列的模式是原始表的模式副本:

enter image description here

步骤2 - 逐个处理分区仅扫描相应列(无全表扫描) - 插入相应分区

#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170101) AS r

从Web UI运行上面的查询,目标表名为mytable $ 20160101

您可以在第二天运行相同的

#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170102) AS r

现在你应该有目标表作为mytable $ 20160102等等

enter image description here

您应该可以使用您选择的任何客户端自动执行/编写此步骤

如何使用上述方法有很多变化 - 这取决于你的创造力

注意:BigQuery允许表中最多10000列,因此一年中相应日期的365列绝对不是问题:o) 除非你对新分区的回程有多少限制 - 我听说(但没有机会检查)现在回来的时间不超过90天

  

更新

请注意: 上面的版本有一点额外的逻辑,将所有聚合单元格打包成尽可能少的最终行数。

ROW_NUMBER() OVER(PARTITION BY d) AS line
然后
GROUP BY line
随着
ARRAY_CONCAT_AGG(…)
这样做

当原始表中的行大小不是那么大时,这种方法很有效,因此最终组合行大小仍然在BigQuery的行大小限制内(我相信现在是10 MB)

如果源表的行大小已接近该限制 - 请使用以下调整后的版本

在此版本中 - 删除分组,使每行只有一列的值

#standardSQL
SELECT
    CASE WHEN d = 'day20170101' THEN r END AS day20170101,
    CASE WHEN d = 'day20170102' THEN r END AS day20170102,
    CASE WHEN d = 'day20170103' THEN r END AS day20170103,
    CASE WHEN d = 'day20170104' THEN r END AS day20170104,
    CASE WHEN d = 'day20170105' THEN r END AS day20170105,
    CASE WHEN d = 'day20170106' THEN r END AS day20170106,
    CASE WHEN d = 'day20170107' THEN r END AS day20170107,
    CASE WHEN d = 'day20170108' THEN r END AS day20170108,
    CASE WHEN d = 'day20170109' THEN r END AS day20170109,
    CASE WHEN d = 'day20170110' THEN r END AS day20170110
FROM (
    SELECT 
        stn, CONCAT('day', year, mo, da) AS d, ARRAY_AGG(t) AS r
    FROM `bigquery-public-data.noaa_gsod.gsod2017` AS t 
    GROUP BY stn, d
)
WHERE d BETWEEN 'day20170101' AND 'day20170110'

正如您现在所看到的 - 数据透视表(sparce_pivot_table)足够稀疏(相同的21.5 MB,但现在是114,089行,而pivot_table中的11,584行),因此它的平均行大小为190B,初始版本为1.9KB。根据示例中的每列数,这显然要少10倍 所以在使用这种方法之前,需要做一些数学计算/估计什么以及如何做!

enter image description here

仍然:数据透视表中的每个单元格都是原始表格中整行的JSON表示形式。它不仅包含原始表中的行的值,而且还包含一个模式

enter image description here

因此它非常冗长 - 因此细胞的大小可能比原始大小大许多倍[这限制了这种方法的使用......除非你变得更有创意:o)......这仍然很充足这里适用的领域:o)]

答案 1 :(得分:7)

在BigQuery中推出新功能之前,还有另一种(便宜得多的)方法可以使用Cloud Dataflow对表进行分区。我们使用这种方法而不是运行数百个SELECT *语句,这将花费我们数千美元。

  1. 使用普通partition命令
  2. 在BigQuery中创建分区表
  3. 创建数据流管道并使用BigQuery.IO.Read接收器来读取表格
  4. 使用Partition transform分区每行
  5. 一次最多使用200个分片/接收器(不超过200个分片/接收器,并达到API限制),为每天/分片创建一个BigQuery.IO.Write接收器,使用分区装饰器写入相应的分区语法 - "$YYYYMMDD"
  6. 重复N次,直到处理完所有数据。
  7. Here's an example on Github让你开始。

    您仍然需要为数据流管道付费,但它只是在BigQuery中使用多个SELECT *的一小部分。

答案 2 :(得分:6)

截至今天,您现在可以通过查询并指定分区列,从非分区表创建分区表。您将在原始(未分区)表上支付一次全表扫描费用。 注意:目前处于测试阶段。

https://cloud.google.com/bigquery/docs/creating-column-partitions#creating_a_partitioned_table_from_a_query_result

  

要从查询结果创建分区表,请将结果写入新目标表。您可以通过查询分区表或非分区表来创建分区表。您无法使用查询结果将现有标准表更改为分区表。

答案 3 :(得分:4)

如果您今天有日期分片表,则可以使用此方法:

https://cloud.google.com/bigquery/docs/creating-partitioned-tables#converting_dated_tables_into_a_partitioned_table

如果要将单个非分区表转换为分区表,则可以尝试运行SELECT *查询并允许大结果并使用表的分区作为目标(类似于如何你重新分区的数据):

https://cloud.google.com/bigquery/docs/creating-partitioned-tables#restating_data_in_a_partition

请注意,此方法会向您收取查询源表的扫描成本,与您查询的次数一样多。

我们正在努力使这种情况在未来几个月内显着改善。

答案 4 :(得分:2)

对我有用的是以下直接在大查询中应用的查询集(大查询创建新查询)。

CREATE TABLE (new?)dataset.new_table PARTITION BY DATE(date_column) AS SELECT * FROM dataset.table_to_copy;

然后下一步,放下表格:

DROP TABLE dataset.table_to_copy;

我从https://fivetran.com/docs/warehouses/bigquery/partition-table获得了此解决方案 仅使用第2步