Update + Insert 比 Upsert 更好?

Update + Insert better than Upsert?

解释:

假设我们有一个 table:

userid points
123 1
456 1

useridpoints 都是 int 类型或任何其他数值数据类型。而userid就是我的PK。
现在,在我的 table 中,我想执行更新查询,如果该行不存在,我想插入该行。如果用户已经存在我想将点数增加 1,否则插入用户 ID 和点数默认为 1。

我知道我可以像这样执行 upsert

INSERT INTO table(userid, points) VALUES(123, 1)
ON conflict (userid)
DO UPDATE
SET points = table.points + 1 
where table.userid = 123;

但是,在我的例子中,更新操作比插入新行更频繁。假设每天有 5000 个查询,其中大约 4500 行是对现有行的 UPDATE 操作。执行与 upsert 相反的操作会更有益,因为冲突会减少到 500 次而不是 4500 次。我想先尝试 UPDATE,如果它 returns UPDATE 0 我想执行 INSERT

是否可以在 单个查询 中使用 RETURNINGFOUND 或其他方式执行上述操作?或者如果可能的话,上述的好处是否太微不足道,upsert 是可行的方法?

我想使用 python 和 asyncpg(2 个查询)做的事情的简单表示:

import asyncio
import asyncpg

async def run():
    conn = await asyncpg.connect(user='user', password='password',
                                 database='database')

    output = await conn.execute("UPDATE table set points = points + 1 where userid = ", 123)

    if output == "UPDATE 0":
        await conn.execute("INSERT INTO table(userid, points) values(, )", 123, 0)

    await conn.close()

loop = asyncio.get_event_loop()
loop.run_until_complete(run())

我已经检查过的问题:

您提议的代码存在竞争条件:有人可以在 UPDATEINSERT 之间插入一行,从而导致两者都失败。唯一安全的技术是无限循环,它会尝试两个语句,直到其中一个成功。

由于每条语句都需要客户端-服务器往返,我怀疑您的代码是否会比 INSERT ... ON CONFLICT 执行得更好。

与其毫无根据地假设 INSERT ... ON CONFLICTUPDATE 慢得多,不如对这两种解决方案进行基准测试。