繁体   English   中英

从非分区表迁移到分区表

[英]Migrating from non-partitioned to Partitioned tables

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

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

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

来自 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  

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

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

在此处输入图片说明

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

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

使用名为 mytable$20160101 的目标表从 Web UI 运行上述查询

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

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

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

在此处输入图片说明

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

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

注意:BigQuery 允许表中最多有 10000 列,因此一年中相应天数的 365 列在这里绝对不是问题:o) 除非对新分区的回溯时间有限制——我听说(但没有''t have chance to check yet) 现在不超过 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 倍。
因此,在使用这种方法之前,需要进行一些数学运算来预测/估计可以做什么以及如何做!

在此处输入图片说明

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

在此处输入图片说明

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

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

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得到了这个解决方案

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

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

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

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

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

这是 Github 上的一个示例,可帮助您入门。

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

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

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

请注意,此方法将向您收取查询的源表扫描成本,次数与查询次数相同。

在接下来的几个月里,我们正在努力使这种情况变得更好。

CREATE TABLE `dataset.new_table`
PARTITION BY DATE(date_column) 
AS SELECT * FROM `dataset.old_table`;

drop table `dataset.old_table`;

ALTER TABLE `dataset.new_table`
RENAME TO old_table;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM