【问题标题】:Most performant way to Insert or Read(if record already exists) in Google Cloud Spanner在 Google Cloud Spanner 中插入或读取(如果记录已存在)的最高效方式
【发布时间】:2023-03-08 03:39:01
【问题描述】:

假设我有一个cars 表,其中vin 是主键。 我想插入一条记录(在事务中)或读取记录(如果已经存在具有相同 PK 的记录)。

如果已经存在具有相同 PK 的记录,那么插入或读取记录的最高效方式是什么?

这是我目前的做法:

案例 A:记录不存在

  1. 插入记录
  2. 返回记录

案例 B:记录已存在

  1. 插入记录
  2. 检查错误是否是由于记录已存在
  3. 阅读记录
  4. 返回记录
const car = { vin: '123', make: 'honda', model: 'accord' };

spannerDatabase.runTransactionAsync(async (databaseTransaction) => {
    try {
        // Try to insert car
        await databaseTransaction.insert('cars', car);
        await databaseTransaction.commit();
        return car;
    } catch (error) {
        await databaseTransaction.end();
        // Spanner "row already exists" error. Insert failed because there is already a record with the same vin(PK)
        if (error.code === 6) {
            // Since the record already exists, I want to read it and return it. Whats the most performant way to do this?
            const existingRecord = await carsTable.read({
                columns: ['vin', 'make', 'model'],
                keys: [car.vin],
                json: true,
            });
            return existingRecord;
        }
    }
})

【问题讨论】:

  • 我认为这是实现您想要做的事情的完美方式。只是插入的一个小问题,您可以使用突变 API (example) 来避免传递事务并避免 commit() 调用。但是,如果您需要更改代码以读取自己的写入 (RYW),那么您将不得不在事务中使用 DML 查询作为RYW is not supported with the mutations API

标签: node.js google-cloud-platform google-cloud-spanner


【解决方案1】:

正如上面评论中提到的@skuruppu,您当前的示例对于您所描述的内容来说大部分都很好。然而,它确实隐含地假设了一些事情,因为您没有在同一个事务中执行读取和插入。这意味着这两个操作一起不是原子的,其他事务可能会更新或删除两个操作之间的记录。

此外,您的方法假设方案 A(记录不存在)是最可能的。如果不是这种情况,并且记录确实存在的可能性相同,那么您应该在写入之前在事务中执行读取。

如果有其他进程可能会删除记录,您也应该这样做。否则,另一个进程可能会在您尝试插入记录之后删除该记录,但在您尝试读取它之前(在事务之外)之前

以上只是一个真正的问题如果有其他进程可能会删除或更改记录。如果不是这样,将来也不会,这只是一个理论上的问题。

总结一下:

  1. 您的示例很好如果场景 A 是最可能的并且没有其他进程将删除 cars 表中的任何记录。
  2. 如果 1 中的任何条件不成立,您应该在写入之前使用相同的读/写事务对两个操作执行读取。

您在示例中使用的read 操作是从表中读取单行的最有效方法。

【讨论】:

    猜你喜欢
    • 2022-01-06
    • 2010-12-29
    • 1970-01-01
    • 2017-07-07
    • 2018-06-19
    • 1970-01-01
    • 2020-01-08
    • 1970-01-01
    • 2010-11-26
    相关资源
    最近更新 更多