【问题标题】:Delete/update table entries by joining 2 tables on Google BigQuery without import/export通过在 Google BigQuery 上加入 2 个表而不导入/导出来删除/更新表条目
【发布时间】:2016-04-22 16:09:40
【问题描述】:

我们有一个用例,其中我们在一个表中有数亿个条目,并且在进一步拆分它时遇到了问题。 99% 的操作是仅追加的。但是,我们偶尔会进行更新和删除,Google 自己说只有删除一个表并使用最新数据创建一个新表才能实现。

因为数据量很大,我们希望在 30 秒左右更新表,所以我们考虑了将 原始表刷新表 连接的可能性> 在某种程度上,我们只有出现在原始表中但不在刷新表中的条目(删除的情况)或使用刷新表中的数据写入项目(如果找到)(更新的情况)。输出/目标应该是新表,然后我们将使用 WRITE_TRUNCATE(覆盖)将其复制回原始表。如果更新似乎太复杂,我们可以使用仅删除逻辑并自己重新插入更新的项目。

这可能吗?哪种类型的连接似乎最合适?我们会将更新插入到 Refresher 表中,并定期清理 Original 表。我们不必为重新插入整个原始表(无论是时间还是金钱)付费,而只需查询一次以及将少数流式插入更新表。

编辑:我们可以忍受查询过时的数据,直到定期合并发生。我们还可以在维护期间暂停查询一小段时间。

欢迎任何想法。

【问题讨论】:

  • 为什么不直接接受更新作为表中的新行,并让查询只读取表中的最后一行?这要容易得多。你考虑过这个吗?
  • 这听起来像是我们应该评估/基准的选项!感谢您的精彩输入。我们必须检查哪一个对我们正在进行的查询的干扰最小。我们仍然对连接如何完成这项工作感兴趣。是反加入吗?

标签: google-bigquery


【解决方案1】:

所以要在我的评论中添加更多内容:

您为什么不直接接受更新作为表中的新行,并且 是否有只读取表中最后一行的查询?太多了 更容易。

像这样创建一个视图:

select * from (
SELECT 
rank() over (partition by user_id order by timestamp desc) as _rank,
*
FROM [db.userupdate_last] 
) where _rank=1

并更新您的查询以查询视图表和您的基本表,然后您就完成了。

我们如何使用它的一些上下文。我们有一个包含用户配置文件数据的事件表。每次更新时,我们都会在 BQ 中再次附加完整的配置文件数据行。这意味着我们最终拥有一个版本化的内容,其中该 user_id 的行数与他们完成的更新数一样多。这都在同一张表中,通过查看时间我们知道更新的顺序。假设我们的表:[userupdate]。如果我们做一个

select * from userupdate where user_id=10

它会以随机顺序将此用户所做的所有更新返回到他们的个人资料中。

但是我们创建了一个视图,我们只创建了一次,语法如上。现在当我们:

select * from userupdate_last where user_id=10 #notice the table name changed to view name

它将只返回 1 行,即用户的最后一行。如果我们想从包含一堆仅附加行的表中查询,我们只需将表名交换为视图名即可查询。

【讨论】:

  • 注意对原始问题的编辑。我们希望让我们的查询保持简单,并在更新的情况下为一个小时左右的陈旧数据付出代价。我们仍然对连接方法感兴趣,因为它不会干扰现有的查询,而无需在所有读取查询上添加诸如 GROUP BY 用户 ID ORDER BY 版本和 LAST() 之类的内容。我们假设与您的方法相比,这将为正常查询节省一两秒。这不正确吗?
  • 因此,如果您将以上内容创建为视图,则在查询中您不需要添加任何 group by 或 order by 或类似的东西,只需更改表名即可。试试这个简单的步骤。我会为我们使用它添加更多上下文。
  • 再次感谢,我们将对此进行评估!看起来如果我们使用简单的 WHERE version IS NULL 进行查询,我们可以以尽可能低的成本(时间和金钱)查询陈旧的数据——尽管您的方法非常有趣,因为它提供了针对实时数据的查询!但是,删除呢?如果我们不必一直按已删除的 IS NULL 之类的东西进行过滤,那就太好了。
  • 过滤如delete为null对BQ没有性能影响,甚至可以直接在视图本身编译
【解决方案2】:

我们发现有一个相对简单的选项在 BigQuery 的类似场景中很有效。
它允许处理基于任何时间快照的查询——以及查询当前快照

简而言之,想法是拥有一个主表和每日历史表
白天 - 当前的每日表用于插入(新、更新、删除),然后每日进程将最后完成的每日表与主表合并,将其写回同一个主表。当然,首先,通过最新主表的副本进行备份(免费操作)。

每日主表更新过程允许在最后一天保持主表清洁和新鲜。
现在,在任何给定时刻,您都可以通过仅查询(无垃圾)主表和仅今天的表来获取最新数据。
同时,由于您拥有所有每日表,您可以查询任何历史数据

当然,将所有数据(新、更新、删除)添加到具有相应限定符的主表中的经典选项在价格和性能方面仍然看起来不错,因为您的主要 (99%) 数据是新条目!

就我个人而言,我会投票支持定期清理历史条目的经典方法

最后,在我看来,与其说是加入,不如说是union 使用table wildcardwindow 函数

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-18
    • 2021-02-16
    • 2011-05-23
    • 2018-05-02
    • 2019-01-01
    • 1970-01-01
    • 2012-10-27
    • 1970-01-01
    相关资源
    最近更新 更多