BigQuery全表分区

use*_*374 4 google-bigquery

我在一个表中有340 GB的数据(270天的数据).现在计划将此数据移动到分区表.

这意味着我将有270个分区.将此数据移动到分区表的最佳方法是什么?

我不想运行270个查询,这是非常昂贵的操作.所以寻找优化的解决方案.

我有这样的多个表.我需要将所有这些表迁移到分区表.

谢谢,

Mik*_*ant 5

我看到三种选择

  1. 从原始表中直接提取:
    操作(要运行多少个查询)=天[提取] = 270个
    完全扫描(在原始表的完整扫描中测量的扫描数据量)=天= 270
    成本,$ = $ 5 x表大小,TB xFull Scans = $ 5 x 0.34 x 270 = $ 459.00

  2. 分层(递归)提取 :(在Mosha的答案中描述)
    动作 = 2 ^ log2(天) - 2 = 510
    完全扫描 = 2*log2(天)= 18
    成本,$ = $ 5 x表大小,TB xFull扫描= $ 5 x 0.34 x 18 = 30.60美元

  3. 集群提取 :(我将在一秒内描述)
    行动 =天+ 1 = 271
    全扫描 = [总是] 2 = 2
    成本,$ = $ 5 x表格大小,TB x全扫描= $ 5 x 0.34 x 2 = $ 3.40

摘要

Method                              Actions Total Full Scans    Total Cost  
Direct Extraction                       270              270       $459.00
Hierarchical(recursive) Extraction      510               18        $30.60
Clustered Extraction                    271                2         $3.40  
Run Code Online (Sandbox Code Playgroud)

当然,对于大多数实际用途来说,Mosha的解决方案是可行的(我在大多数情况下使用它)
它相对简单直接

即使你需要运行510次查询- 查询"相对"简单,并且编排逻辑很容易实现,无论你经常使用什么客户端
,成本保存是非常明显的!从$ 460降至$ 31!
差不多15次了!

如果您 -
a)想要进一步降低成本9倍(因此它将总共降低x135倍)
b)并且喜欢享受乐趣和更多挑战 - 请看第三个选项

"集群提取"解释

想法/目标:
步骤1
我们希望将原始表格转换为另一个具有270列的[单个]表格 - 一列中的一
列每列将从原始表格中保存一个序列化
的行,这个新表格中的总行数将是等于大多数"重"日的行数
这将只需要一次查询(参见下面的示例)并进行一次完整扫描

步骤2 在新表准备好之后 - 我们将逐日查询各自的列并写入最终的每日表(每日表的模式与原始表的模式完全相同,所有这些表都可以预先创建这将需要运行270个查询,扫描大致相当(这实际上取决于您的架构的复杂程度,因此可能会有所不同)到原始表的一个完整大小查询列时 - 我们需要反序列化行的值并解析它回到原来的计划

非常简单的例子 :(在这里使用BigQuery Standard SQL)

这个例子的目的只是为了给你提供指导,如果你会发现你的想法很有意义
序列化/反序列化非常简化以保持专注于想法而不是特定的实现,这可能因情况而异(主要取决于模式)

因此,假设原始表(theTable)看起来有点像下面

  SELECT  1 AS id, "101" AS x, 1 AS ts UNION ALL
  SELECT  2 AS id, "102" AS x, 1 AS ts UNION ALL
  SELECT  3 AS id, "103" AS x, 1 AS ts UNION ALL
  SELECT  4 AS id, "104" AS x, 1 AS ts UNION ALL
  SELECT  5 AS id, "105" AS x, 1 AS ts UNION ALL
  SELECT  6 AS id, "106" AS x, 2 AS ts UNION ALL
  SELECT  7 AS id, "107" AS x, 2 AS ts UNION ALL
  SELECT  8 AS id, "108" AS x, 2 AS ts UNION ALL
  SELECT  9 AS id, "109" AS x, 2 AS ts UNION ALL
  SELECT 10 AS id, "110" AS x, 3 AS ts UNION ALL
  SELECT 11 AS id, "111" AS x, 3 AS ts UNION ALL
  SELECT 12 AS id, "112" AS x, 3 AS ts UNION ALL
  SELECT 13 AS id, "113" AS x, 3 AS ts UNION ALL
  SELECT 14 AS id, "114" AS x, 3 AS ts UNION ALL
  SELECT 15 AS id, "115" AS x, 3 AS ts UNION ALL
  SELECT 16 AS id, "116" AS x, 3 AS ts UNION ALL
  SELECT 17 AS id, "117" AS x, 3 AS ts UNION ALL
  SELECT 18 AS id, "118" AS x, 3 AS ts UNION ALL
  SELECT 19 AS id, "119" AS x, 4 AS ts UNION ALL
  SELECT 20 AS id, "120" AS x, 4 AS ts
Run Code Online (Sandbox Code Playgroud)

第1步 - 转换表并将结果写入tempTable

SELECT 
  num, 
  MAX(IF(ts=1, ser, NULL)) AS ts_1, 
  MAX(IF(ts=2, ser, NULL)) AS ts_2, 
  MAX(IF(ts=3, ser, NULL)) AS ts_3, 
  MAX(IF(ts=4, ser, NULL)) AS ts_4
FROM (
  SELECT 
    ts, 
    CONCAT(CAST(id AS STRING), "|", x, "|", CAST(ts AS STRING)) AS ser, 
    ROW_NUMBER() OVER(PARTITION BY ts ORDER BY id) num
  FROM theTable
)
GROUP BY num
Run Code Online (Sandbox Code Playgroud)

tempTable如下所示:

num    ts_1        ts_2         ts_3        ts_4     
1   1|101|1     6|106|2     10|110|3    19|119|4     
2   2|102|1     7|107|2     11|111|3    20|120|4     
3   3|103|1     8|108|2     12|112|3        null     
4   4|104|1     9|109|2     13|113|3        null     
5   5|105|1        null     14|114|3        null     
6      null        null     15|115|3        null     
7      null        null     16|116|3        null     
8      null        null     17|117|3        null     
9      null        null     18|118|3        null    
Run Code Online (Sandbox Code Playgroud)

在这里,我使用简单的串联进行序列化

第2步 - 提取特定日期的行并将输出写入相应的日常表
请注意:在下面的示例中 - 我们提取ts = 2的行:这对应于列ts_2

SELECT
  r[OFFSET(0)] AS id,
  r[OFFSET(1)] AS x,
  r[OFFSET(2)] AS ts
FROM (
  SELECT SPLIT(ts_2, "|") AS r 
  FROM tempTable 
  WHERE NOT ts_2 IS NULL
)
Run Code Online (Sandbox Code Playgroud)

结果将如下所示(预期):

id    x    ts    
6   106     2    
7   107     2    
8   108     2    
9   109     2   
Run Code Online (Sandbox Code Playgroud)

我希望我有更多的时间来写下来,所以如果缺少某些东西,不要判断重 - 这是更有方向性的答案 - 但同时示例是非常合理的,如果你有简单的架构 - 几乎没有额外的想法是必须的.当然有了记录,架构中的嵌套东西 - 最具挑战性的部分是序列化/反序列化 - 但这就是有趣的地方 - 以及额外的$节省


Mos*_*sky 1

如果您的数据位于分片表中(即带有YYYYmmdd后缀),您可以使用"bq partition"命令。但对于单个表中的数据 - 您将必须在分区键列上应用不同的 WHERE 子句多次扫描它。我能想到的唯一优化是分层执行,即不是 270 个查询,而是执行 270 次全表扫描 - 首先将表分成两半,然后将每一半分成两半,等等。这样您将需要支付2*log_2(270) = 2*9 = 18全表扫描的费用。

转换完成后,可以删除所有临时表以消除额外的存储成本。