我想将以下 - 不可思议的错误查询从H2 / MySQL转换为Postgres / cockroach:
SET @UPDATE_TRANSFER=
(select count(*) from transfer where id=‘+transfer_id+' and consumed=false)>0;
update balance_address set balance =
case when @UPDATE_TRANSFER then balance +
(select value from transaction where transfer_id=‘+id+' and t_index=0)
else balance end where address =
(select address from transaction where transfer_id=‘+id+' and t_index=0)
此查询涉及三个表: balance_address , bundle 和 transaction 。查询的目标是在资金转移发生时更新总体余额。
转移可以将许多交易捆绑在一起。例如,让我们假设保罗在他的账户中有20美元,他想向Jane发送3美元。这将导致4笔交易: 一个为Jane的帐户增加3美元 一笔交易从保罗账户中删除了20美元 一个将Paul帐户更改为0的交易 一项交易,将剩余的保罗资金投入新地址;仍然属于他。
整个转移捆绑中的每个事务都有一个索引和一个值。如上所述。因此,此更新查询的目标是更新Jane的帐户。
挑战在于,这种传输可以由许多服务器并行处理,并且没有分布式锁。因此,如果我们天真地并行处理,每个服务器都会增加Jane的帐户,从而导致错误的结果。
为了防止这种情况,balance_address表有一个名为consume的列。更新余额的第一台服务器将传输设置为consume = true。其他服务器或线程只能在消耗为false时更新。
所以,我的目标是1)改进这个查询,2)重写它以使用海报。现在,不接受变量构造。
PS。我无法改变数据模型。
答案 0 :(得分:1)
CockroachDB没有变量,但@UPDATE_TRANSFER
变量只使用一次,所以你可以直接替换子查询:
update balance_address set balance =
case
when (select count(*) from transfer where id=$1 and consumed=false)>0
then balance + (select value from transaction where transfer_id=$1 and t_index=0)
else balance
end
where address =
(select address from transaction where transfer_id=$1 and t_index=0)
但是这并没有设置consumed
标志。最简单的方法是在客户端应用程序中进行多步骤事务:
num_rows = txn.execute("UPDATE transfer SET consumed=true
WHERE id=$1 AND consumed=false", transfer_id)
if num_rows == 0: return
value, address = txn.query("SELECT value, address FROM transaction
WHERE transfer_id=$1 and t_index=0", transfer_id)
txn.execute("UPDATE balance_address SET balance = balance+$1
WHERE address = $2", value, address)
在PostgreSQL中,我认为你可以使用公共表表达式将它变成一个大的语句。但是,CockroachDB 2.0仅支持一部分CTE,我不认为用蟑螂中的CTE可以做到这一点。