2016-08-17 109 views
6

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

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

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

+2

的,使用R的人,下面是自动生成接受的答案所需的代码要点:https://gist.github.com/anonymous/8e6541433b345c798df20b638ae98b3a#file-gistfile1-txt希望这节省了一些人的时间 – rmg

+0

上述要点还在RStudio的博客文章中进一步开发:https://rviews.rstudio.com/2018/02/02/cost-effective-bigquery-with-r/ – rmg

回答

6

from Pavan’s answer: Please note that this approach will charge you the scan cost of the source table for the query as many times as you query it.


from Pentium10 comments: So suppose I have several years of data, I need to prepare different query for each day and run all of it, and suppose I have 1000 days in history, I need to pay 1000 times the full query price from the source table?


正如我们看到的 - 这里的主要问题是在具有对每一天全扫描。剩下的就是一个问题较少,并可以在任何client of the choice

所以很容易编写而成,下面是 - 如何分区表,同时避免全表扫描的每一天?

下面一步一步的显示方式

它是通用的,足以扩展/适用于任何实际使用情况 - 同时我使用bigquery-public-data.noaa_gsod.gsod2017,我限制“演习”,以仅10天保持它可读

步骤1 - 创建透视表
在此步骤中,我们
一)压缩每行的内容到记录/阵列

二)把他们都到各自的“日报”列

#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 

运行上面的查询中的Web UI与pivot_table(或任何名称是首选)作为目的地

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

enter image description here

个步骤2 - 处理一个分区接一个ONLY扫描各自的列(没有全表扫描) - 插入相应的分区,从网络用户界面与目的地表格上述查询

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

运行名为MyTable $二千〇十六万〇一百〇一

您可以第二天运行相同

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

现在你应该有目标表为MYTABLE $二零一六零一零二等

enter image description here

你应该能够自动/脚本这一步与您选择的任何客户端

有如何,您可以使用上面的方法很多变化 - 它是由你的创造力

注:BigQuery最多允许在表格中填写10000列,因此在一年中的相应日期365列绝对不是问题:o) 除非您对新分区的使用距离有限 - 我听说过(但没有没有机会检查)现在不超过90天返回

Update

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

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

这种运作良好,当你的原始表行大小是没有那么大那么最终结合的行大小仍然是内BigQuery具有的行大小限制(我相信现在是10 MB)

如果您的源ta BLE已经有行大小接近极限 - 使用下面的调整版本

在这个版本 - 分组被删除,使得每行只有一列

#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)]

+0

哇。现在就去测试一下。 Mikhail是什么工具/ UI? –

+0

@GrahamPolley - 已经很久没有使用BigQuery Web UI了,这btw并没有帮助我保持良好的BQ Mate,所以我真的依赖于用户的反馈 - 仍然试图保持更新并在知道时进行修复需要和有一些空闲时间。 –

+0

@GrahamPolley - 作为 - “这是什么工具/ UI?” - 这是我必须根据业务用户的需求创建的几个工具之一(当然我的团队) - 这补偿了Google Web UI中缺少的许多功能。当它不能按需要执行时,我们会达到这个程度 - 甚至大部分会在我们的体积和规模上崩溃。我们已经/已经使用这些工具已经有好几年了--BQ团队正在慢慢增加一些功能/改进,但仍然远远不够我们需要(并且在我们的内部工具中) –

2

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

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

如果你有一个非分区表转换为分区表,你可以尝试运行的方法a。选择与允许较大的结果*查询和使用表的分区目标(类似于你如何重新公布一个分区中的数据):

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

请注意这种方法会按照您查询的次数向您收取查询源表的扫描成本。

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

+0

我如何确保第二种方式是模式是DAY?除了DAY以外还有其他什么类型的? – Pentium10

+0

目前我们只支持DAY粒度,因为这在历史上一直是最常见的使用模式。 我可能误解了你的问题,但你可以使用模式预先创建表,例如: bq mk --schema =“field1:integer,field2:string”--time_partitioning_type = DAY mydataset.table1 –

+0

好,所以我需要用分区创建一个新表,然后选择*,这将保留我们拥有的所有重复和嵌套类型,对吧? – Pentium10

4

在BigQuery中推出新功能之前,通过使用Cloud Dataflow还有另一种(更便宜)的方法来分区表。我们使用这种方法,而不是运行数百个SELECT *报表,这会花费我们数千美元。

  1. BigQuery中创建分区表使用正常partition命令
  2. 创建一个数据流管道并使用BigQuery.IO.Read沉读取表
  3. 使用Partition transform分割每行
  4. 使用最多的每次200个shards/sinks(超过这个数量并且达到API限制),为每个日子/分片创建一个BigQuery.IO.Write接收器,它将使用分区装饰器语法写入相应分区 - "$YYYYMMDD"
  5. 重复N次,直到处理完所有数据。

Here's an example on Github让你开始。

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

+0

我相信这个选项只适用于日期分片表。我是对的? – YABADABADOU

+1

@YABADABADOU不,它可以在任何**表上使用。 –

+0

hi @GrahamPolley,基于你的方法我写了自己的一个关键文件分割文件。当我分裂100他们是没有问题的,但如果我分裂在1000我收到此味精; '警告:root:重试指数退避:在重试submit_job_description之前等待2.82656908647秒,因为我们发现异常:错误:[Errno 32] Broken pipe'你有这种问题吗?堆栈上的第一个错误:'__ProcessHttpResponse http_response.request_url,method_config,request) apitools.base.py.exceptions.HttpError: danihp

3

截至今天,你现在可以通过查询并指定分区列,从非分区表创建分区表。 注意:这是目前在测试版。

To create a partitioned table from a query result, write the results to a new destination table. You can create a partitioned table by querying either a partitioned table or a non-partitioned table. You cannot change an existing standard table to a partitioned table using query results.