Google Cloud Spanner 中的增量值
Increment values in 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+行的批量写入性能相比,缓慢的多行解决方案确实令人难过。
没有一种直接的方法可以满足您的需求。
探索一个选项以确保我们获得合理的吞吐量:
- 读取所有要更新或插入的键。
- 根据 insert/update 语句的结果构造一个 BatchDML
从第 1 步开始阅读。
- 请注意,更新必须是有条件的更新。
示例:"UPDATE table SET value = {prev_value} +1 WHERE key = "ABC"
AND 值 = {prev_value}";
执行构造的 BatchDML。请注意,某些语句可能会失败。
如果键已经存在,插入可能会失败:我相信这应该不是问题,因为键已经存在(这是插入尝试的预期结果)。
如果值在我们读取时发生变化,则可能不会发生更新。如果我们重复这个循环,更新可以在下一批发生。
如您所见,这有一些注意事项。
我正在使用 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+行的批量写入性能相比,缓慢的多行解决方案确实令人难过。
没有一种直接的方法可以满足您的需求。
探索一个选项以确保我们获得合理的吞吐量:
- 读取所有要更新或插入的键。
- 根据 insert/update 语句的结果构造一个 BatchDML 从第 1 步开始阅读。
- 请注意,更新必须是有条件的更新。 示例:"UPDATE table SET value = {prev_value} +1 WHERE key = "ABC" AND 值 = {prev_value}";
执行构造的 BatchDML。请注意,某些语句可能会失败。
如果键已经存在,插入可能会失败:我相信这应该不是问题,因为键已经存在(这是插入尝试的预期结果)。
如果值在我们读取时发生变化,则可能不会发生更新。如果我们重复这个循环,更新可以在下一批发生。
如您所见,这有一些注意事项。