google-cloud-spanner - Google Cloud Spanner 中的增量值
问题描述
我正在使用 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
似乎也不可能通过突变增加。这只会创建行或覆盖值:
db.transaction do |tx|
tx.upsert "test", [{ key: 'ABC', value: 1 }]
end
有什么办法可以用 Spanner 做我需要的事情吗?与每秒 100k+ 行的批量写入性能相比,缓慢的多行解决方案真的很可悲。
解决方案
没有一种简单的方法可以完成您所需要的。
探索一种选择以确保我们获得合理的吞吐量:
- 读取所有要更新或插入的键。
- 根据步骤#1 的读取结果,构造一个带有一堆插入/更新语句的 BatchDML。
- 请注意,更新必须是有条件的更新。示例:“UPDATE table SET value = {prev_value} +1 WHERE key = "ABC" AND value = {prev_value}";
执行构造的 BatchDML。请注意,某些语句可能会失败。
如果密钥已经存在,插入可能会失败:我相信这应该不是问题,因为密钥存在(这是插入尝试的预期结果)。
如果值从我们读取的时间开始发生变化,则可能不会发生更新。如果我们重复这个循环,更新可能会在下一批中发生。
如您所见,这带有警告。
推荐阅读
- python - 尝试循环内的语句不起作用python
- java - 预期状态:<302> 但原为:<405>
- python - PySpark - 读取镶木地板文件但不是同一文件夹中的另一个?
- sql-server - ADO 失败第二次通过循环
- python - python中带有装饰器的令人困惑的代码执行路径
- python - 错误 ValueError: 尝试使用 cross_val_score 和线性回归时不支持连续
- python - 如何创建一个文件对话框,返回所选文件和目录的文件路径?
- python - 如何仅使用基类中的方法/装饰器计算python中被覆盖的方法所花费的时间?
- or-tools - CP-SAT 在创建目标函数时很慢
- css - 在动画期间减小图标的大小