从非分区表迁移到分区表

Pen*_*m10 14 google-bigquery

6月,BQ团队宣布支持日期分区表.但是指南缺少如何将旧的非分区表迁移到新样式中.

我正在寻找一种方法来更新几个或如果不是所有表到新的样式.

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

小智 15

对我有用的是以下一组直接应用于大查询的查询(大查询创建新查询)。

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

然后作为下一步,我放下桌子:

DROP TABLE dataset.table_to_copy;

我 只使用第 2 步从https://fivetran.com/docs/warehouses/bigquery/partition-table得到了这个解决方案

  • 值得庆幸的是,我在尝试接受的答案之前看到了您的答案。 (4认同)

Mik*_*ant 14

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


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


我们可以看到 - 这里的主要问题是每天都要进行全面扫描.剩下的不是问题,可以在任何选择的客户端轻松编写脚本

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

下面逐步说明该方法

它足够通用,可以扩展/适用于任何真正的用例 - 同时我正在使用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  
Run Code Online (Sandbox Code Playgroud)

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

我们可以看到 - 这里我们将得到10列的表 - 一天一列,每列的模式是原始表的模式的副本:

在此输入图像描述

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

#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170101) AS r
Run Code Online (Sandbox Code Playgroud)

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

你可以在第二天运行

#standardSQL
SELECT r.*
FROM pivot_table, UNNEST(day20170102) AS r
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

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

注意: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'
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

在此输入图像描述

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


Gra*_*ley 7

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

  1. 使用normal partition命令在BigQuery中创建分区表
  2. 创建数据流管道并使用接收BigQuery.IO.Read器读取表
  3. 使用分区转换来分区每一行
  4. 一次最多使用200个分片/接收器(不超过这个并且达到API限制),BigQuery.IO.Write为每天/分片创建一个接收器,使用分区装饰器语法写入相应的分区 -"$YYYYMMDD"
  5. 重复N次,直到处理完所有数据.

这是Github上一个让你入门的例子.

您仍然需要为Dataflow管道付费,但这只是SELECT *在BigQuery 中使用多个成本的一小部分.


Gra*_*ley 6

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

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

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


Pav*_*ara 5

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

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认同)
  • 那么假设我有几年的数据,我需要为每一天准备不同的查询并运行所有查询,假设我有 1000 天的历史记录,我需要支付源表完整查询价格的 1000 倍?如果这是真的,那就是“难以置信”。 (2认同)