【问题标题】:Increment values in Google Cloud SpannerGoogle Cloud Spanner 中的增量值
【发布时间】:2020-02-16 11:40:26
【问题描述】:

我正在使用 Google Cloud Spanner,我需要一种将行的值增加 value = value + 1 的方法。 事实证明这是一个令人头疼的问题,因为我看不到检查该行是否已存在的方法。 我正在使用 Ruby 客户端库(gem 版本 1.13.1)

目前我有以下代码可以完成这项工作,但速度仅为每秒 40-50 次事务。 我看不到批处理的方法,因为据我所知,我只能批处理单个 DML 语句。

db.transaction do |transaction|
  if transaction.execute_query("SELECT value FROM table WHERE key = 'ABC'").rows.first.to_h[:value]
    transaction.execute_update("UPDATE table SET value = value + 1 WHERE key = 'ABC'")
  else
    transaction.execute_update("INSERT INTO table (key, value) VALUES ('ABC', 1)")
  end
end

不幸的是,似乎根本不支持用一条语句解决这个问题的 SQL。 (我收到Google::Cloud::InvalidArgumentError (3:Syntax error: Unexpected keyword ON

db.transaction do |tx|
  tx.batch_update do |b|
    b.batch_update(
      "INSERT INTO table (key, value) VALUES ('ABC', 1) ON DUPLICATE KEY UPDATE value = value + 1"
    )
  end
end

似乎也无法通过 Mutations 增加。这只会创建行或覆盖值:

db.transaction do |tx|
  tx.upsert "test", [{ key: 'ABC', value: 1 }]
end

有什么方法可以用 Spanner 做我需要的事情吗? 与每秒 100k+ 行的批量写入性能相比,缓慢的多行解决方案真的很可悲。

【问题讨论】:

    标签: google-cloud-spanner


    【解决方案1】:

    没有一种简单的方法可以满足您的需求。

    探索一个选项以确保我们获得合理的吞吐量:

    1. 读取所有要更新或插入的键。
    2. 根据结果构造一个带有一堆插入/更新语句的 BatchDML 从第 1 步开始读取。
    3. 请注意,更新必须是有条件的更新。 示例:“更新表 SET 值 = {prev_value} +1 WHERE 键 = “ABC” AND 值 = {prev_value}";
    4. 执行构造的 BatchDML。请注意,某些语句可能会失败。

      如果密钥已经存在,插入可能会失败:我相信这应该不是问题,因为密钥存在(这是插入尝试的预期结果)。

      如果值从我们读取的时间开始发生变化,则可能不会发生更新。如果我们重复这个循环,下一批更新可能会发生。

    如您所见,这有一些注意事项。

    【讨论】:

      猜你喜欢
      • 2017-07-05
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-28
      • 2021-05-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多