google-bigquery - 如何分片BigQuery表?

标签 google-bigquery sharding

抱歉,如果其他地方都没有回答,我找不到类似的东西。

有什么方法可以将表拆分为多个分片,而不必使用多个查询?这是两个示例:

1)加载带有时间戳数据(unix时间戳)的表。我想每天将数据保存到一张表中。天真的方法是:a)加载数据; b)运行查询以获取每天的所有数据并将其附加到适当的分片中。这种方法将导致查询触及N x [整个表的大小]数据,其中N是表中的天数。再加上一个查询以查找最小和最大时间戳,以便我可以确定需要创建的分片的范围。

2)使用字段中的数据将表拆分为碎片。例如,一个10亿行的表,其中包含具有1,000个不同值的字段X。如果我想将表拆分为1000个不同的表(每个X值一个表),那么幼稚的方法是运行SELECT * FROM table WHERE X = [value],然后将结果插入到table_value碎片中。但是,这将导致1000个查询,每个查询都涉及整个表的数据!

当然,我缺少一些东西,并且必须有更有效的方法来完成上述操作。

最佳答案

A要求:

让我们假设以下简化的案例/场景

1我们有一个“大”表:
表格全部

Row a   b   c
1   1   11  12
2   1   13  14
3   1   15  16
4   1   17  18
5   2   21  22
6   2   23  24
7   2   25  26
8   2   27  28
9   3   31  32
10  3   33  34
11  3   35  36
12  3   37  38

2我们需要将数据拆分为单独的“较小”表,这些表由归档的“a”分区
表A1
Row b   c
1   11  12
2   13  14
3   15  16
4   17  18

表A2
Row b   c
1   21  22
2   23  24
3   25  26
4   27  28

表A3
Row b   c
1   31  32
2   33  34
3   35  36
4   37  38

3问题要解决
最直接的方法是发出三个单独的语句,分别将输出写入TableA1,TableA2,TableA3
SELECT b, c FROM TableAll WHERE a = 1;
SELECT b, c FROM TableAll WHERE a = 2;
SELECT b, c FROM TableAll WHERE a = 3;

优点:速度与激情!
缺点:我们需要对整个表进行全表扫描(全额费用),而要获得与“a”不同的值(在这种情况下只有三个,但在现实生活中最多可以说N = 1K个不同的值)一样多。

因此最终成本为 $ 5 * N * SizeInTB(TableAll)

Our Target Goal


We want to minimize cost as much as possible 
ideally down to fixed price of $5 * SizeInTB(TableAll)  

B可能的解决方案(想法和简单实现):

逻辑步骤1 –转换要显示的数据(将列转换为JSON)
Row a   json
1   1   {"b":"11", "c":"12"}
2   1   {"b":"13", "c":"14"}
3   1   {"b":"15", "c":"16"}
4   1   {"b":"17", "c":"18"}
5   2   {"b":"21", "c":"22"}
6   2   {"b":"23", "c":"24"}
7   2   {"b":"25", "c":"26"}
8   2   {"b":"27", "c":"28"}
9   3   {"b":"31", "c":"32"}
10  3   {"b":"33", "c":"34"}
11  3   {"b":"35", "c":"36"}
12  3   {"b":"37", "c":"38"}

逻辑步骤2 –枢纽分析表,使栏位“a”的值成为栏位名称(以a开头,以确保我们遵守栏位名称惯例)
Row a1                    a2                    a3
1   {"b":"11", "c":"12"}  null                  null
2   {"b":"13", "c":"14"}  null                  null
3   {"b":"15", "c":"16"}  null                  null
4   {"b":"17", "c":"18"}  null                  null
5   null                  {"b":"21", "c":"22"}  null
6   null                  {"b":"23", "c":"24"}  null
7   null                  {"b":"25", "c":"26"}  null
8   null                  {"b":"27", "c":"28"}  null
9   null                  null                  {"b":"31", "c":"32"}
10  null                  null                  {"b":"33", "c":"34"}
11  null                  null                  {"b":"35", "c":"36"}
12  null                  null                  {"b":"37", "c":"38"}

注意:以上数据的大小与原始表的大小相同(无a列)
它仍然比原始数据大,因为数据现在是详细的json格式,而不是 native 数据类型+列名。
可以通过消除空格,不需要的引号,规范化/最小化原始列名称以使其名称中只有一个字符等来优化此方法。
我认为随着N的增加,这种差异可以忽略不计! (虽然没有机会对此进行评估)

步骤3 –将结果数据透视表保留到表TableAllPivot中
实现示例:
SELECT 
  IF(a=1, json, NULL) as a1,
  IF(a=2, json, NULL) as a2,
  IF(a=3, json, NULL) as a3 
FROM (
  SELECT a, CONCAT("{\"b\":\"",STRING(b), "\","," \"c\":\"", STRING(c), "\"}") AS json 
  FROM TableAll
)

步骤3的成本:$5 * TableAllSizeInTB基于第2步中的注释,假设:Size(TableAllPivot) = 2 * Size(TableAll)
步骤4 –通过仅查询每个分片一列来产生分片
为了保留模式/数据类型–可以预先创建相应的分片表

数据提取:
//对于TableA1:
SELECT 
  JSON_EXTRACT_SCALAR(a1, '$.b') AS b, 
  JSON_EXTRACT_SCALAR(a1, '$.c') AS c 
FROM TableAllPivot
WHERE NOT a1 IS NULL

//对于TableA2:
SELECT 
  JSON_EXTRACT_SCALAR(a2, '$.b') AS b, 
  JSON_EXTRACT_SCALAR(a2, '$.c') AS c 
FROM TableAllPivot
WHERE NOT a2 IS NULL

//对于TableA3:
SELECT 
  JSON_EXTRACT_SCALAR(a3, '$.b') AS b, 
  JSON_EXTRACT_SCALAR(a3, '$.c') AS c 
FROM TableAllPivot
WHERE NOT a3 IS NULL

第4步的费用:$5 * TableAllPivot
总费用:Step 3 Cost + Step 4 Cost =$5 * SizeInTB(TableAll) + $5 * SizeInTB(TableAllPivot)$5 * 3 * SizeInTB(TableAll)
摘要:
拟议方法固定价格= $5 * 3 * SizeInTB(TableAll)
初始线性价格= $5 * N * SizeInTB(TableAll)
请注意:在我的简化示例中,3公式中的$5 * 3 * SizeInTB(TableAll)不是由分片数定义的,而是估计常数,主要反射(reflect)了将数据转换为json的代价。分片的数量在这里无关紧要。相同的公式适用于100个分片和1K个分片,依此类推。此解决方案中的唯一限制是10K分片,因为这是一个表中列数的硬限制

C一些帮助程序代码和引用:

1个产生数据透视查询(结果在上面的第3步中使用)
当手动键入查询很无聊时,对于初始表中的字段数大于10-20的字段可能很有用,因此可以在下面的脚本/查询中使用
SELECT 'SELECT ' + 
   GROUP_CONCAT_UNQUOTED(
      'IF(a=' + STRING(a) + ', json, NULL) as a' + STRING(a) 
   ) 
   + ' FROM (
 SELECT a, 
 CONCAT("{\\\"b\\\":\\\"\",STRING(b),"\\\","," \\\"c\\\":\\\"\", STRING(c),"\\\"}") AS json
 FROM TableAll
       )'
FROM (
  SELECT a FROM TableAll GROUP BY a 
)

2如果您想探索并深入研究此选项-另请参见以下对此处相关且可能有用的代码的引用

Pivot Repeated fields in BigQuery
How to scale Pivoting in BigQuery?
How to extract all the keys in a JSON object with BigQuery

关于google-bigquery - 如何分片BigQuery表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34955071/

相关文章:

google-cloud-platform - 在 BigQuery 中使用大偏移量

go - 权限被拒绝使用 API key 从 GAE 使用 Go 访问 Bigquery

scala - Akka Stateful Actor 跨节点复制

java - 设置分片orientdb

java - 如何在 java-mongodb 驱动程序中为 find 提供提示

google-bigquery - 如何从 ARRAY 中排除 NULL 以便查询不会失败

sql - 每组 LIMIT - Google BigQuery/标准 SQL

sql - BigQuery - 连接每行的字符串数组

sql-server - SQL Server 是否支持分片?

mongodb - mongodb 中的主分片