Преобразование запроса H2 / MySQL в Postgres / таракан - PullRequest
0 голосов
/ 11 июня 2018

Я хочу преобразовать следующий - по общему мнению, плохой - запрос из 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 , связка и транзакция .Целью запроса является обновление общего баланса, когда происходит перевод средств.

В перевод может быть включено много транзакций.Например, предположим, что у Пола есть 20 долларов на его счету, и он хочет послать 3 доллара Джейн.Это приведет к 4 транзакциям: та, которая добавляет 3 доллара на счет Джейн. Одна транзакция, которая удаляет 20 долларов со счета Пола. Одна транзакция, которая заменяет счет Пола на 0. Одна транзакция, которая переводит остаток средств Пола в новый адрес;все еще принадлежит ему.

Каждая из этих транзакций во всем пакете передачи имеет индекс и значение.Как вы видите выше.Таким образом, цель этого запроса на обновление состоит в том, чтобы обновить учетную запись Джейн.

Сложность заключается в том, что эта передача может обрабатываться многими серверами параллельно, и распределенная блокировка отсутствует.Таким образом, если мы наивно обрабатываем параллельно, каждый сервер будет увеличивать учетную запись Джейн, что приводит к ошибочным результатам.

Чтобы предотвратить это, в таблице balance_address есть столбец с именем потребляемый.Первый сервер, который обновляет баланс, устанавливает для передачи значение = истина.Другие серверы или потоки могут обновляться только в том случае, если для потребителя задано значение false.

Итак, моя цель: 1) улучшить этот запрос и 2) переписать его для работы с постерами.Прямо сейчас, переменная конструкция уже не принята.

PS.Я не могу изменить модель данных.

1 Ответ

0 голосов
/ 13 июня 2018

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 в таракане.

...