Обсуждение: SELECT FOR UPDATE без транзакции
а можно ли применять SELECT FOR UPDATE в составных запросах? то есть транзакцию не объявляем/начинаем, а пишем однократный автокоммит-запрос, нечто вроде: WITH "s1" AS ( -- тут блокируемся SELECT * FROM "t" WHERE id = $1 FOR UPDATE ), "v1" AS ( -- тут вычисляем значение SELECT SUM("v") AS "v" FROM "t2" WHERE "bla" = $2 ) UPDATE -- а дальше собственно update "t" SET "v" = (SELECT v FROM v1) FROM "s1" WHERE "t"."id" = "s1"."id" -- . ''`. Dmitry E. Oboukhov <unera@debian.org> : :’ : `. `~’ GPG key: 4096R/08EEA756 2014-08-30 `- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756
Вложения
Привет Вы в принципе не можете сделать select вне транзакции. Если вы делаете запрос вне транзакции - этот запрос будет обёрнутв отдельную транзакцию автоматически. Не представляю зачем в вашем примере мог быть нужен s1 вообще - но да, так брать блокировку возможно. С уважением, Сергей
> Привет > Вы в принципе не можете сделать select вне транзакции. Если вы делаете > запрос вне транзакции - этот запрос будет обёрнут в отдельную транзакцию > автоматически. ну я примерно так и думал, просто решил уточнить :) > Не представляю зачем в вашем примере мог быть нужен s1 вообще - но да, > так брать блокировку возможно. Я немного неудачно пример записал. в моём случае второй запрос еще должен сделать insert в t2 на самом деле. то есть полеый алгоритм такой: 1. ставим лок на запись t1 2. записываем новую запись t2 3. аггрегатором вычисляем по t2 значение 4. модифицируем запись в t1 на которую поставили лок (условно говоря первая таблица - таблица со значениями неких счетчиков, вторая таблица - таблица с логом операций над счетчиками) В целом у меня подобная система работает без блокировок, но на одном процессе (конкурентность отстуствует). Сейчас хочу запустить второй параллельный процесс. Он будет очень редко пересекаться по ID записей, однако поскольку пересечения возможны - задумался над локами. -- . ''`. Dmitry E. Oboukhov <unera@debian.org> : :’ : `. `~’ GPG key: 4096R/08EEA756 2014-08-30 `- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756
Вложения
>2. записываем новую запись t2
>3. аггрегатором вычисляем по t2 значение
важно понимать что на шаге 3 вы не увидите записи вставленные на шаге 2>3. аггрегатором вычисляем по t2 значение
13 апреля 2018 г., 14:24 пользователь Dmitry E. Oboukhov <unera@debian.org> написал:
> Привет
> Вы в принципе не можете сделать select вне транзакции. Если вы делаете
> запрос вне транзакции - этот запрос будет обёрнут в отдельную транзакцию
> автоматически.
ну я примерно так и думал, просто решил уточнить :)
> Не представляю зачем в вашем примере мог быть нужен s1 вообще - но да,
> так брать блокировку возможно.
Я немного неудачно пример записал.
в моём случае второй запрос еще должен сделать insert в t2 на самом
деле.
то есть полеый алгоритм такой:
1. ставим лок на запись t1
2. записываем новую запись t2
3. аггрегатором вычисляем по t2 значение
4. модифицируем запись в t1 на которую поставили лок
(условно говоря первая таблица - таблица со значениями неких
счетчиков, вторая таблица - таблица с логом операций над счетчиками)
В целом у меня подобная система работает без блокировок, но на одном
процессе (конкурентность отстуствует). Сейчас хочу запустить второй
параллельный процесс. Он будет очень редко пересекаться по ID записей,
однако поскольку пересечения возможны - задумался над локами.
--
. ''`. Dmitry E. Oboukhov <unera@debian.org>
: :’ :
`. `~’ GPG key: 4096R/08EEA756 2014-08-30
`- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756
--
All bugs reserved
>> 2. записываем новую запись t2 >> 3. аггрегатором вычисляем по t2 значение > важно понимать что на шаге 3 вы не увидите записи вставленные на шаге 2 почему - увижу, returning в insert же есть. но тут главный вопрос обеспечить корректность при конкуренции. вопрос: а насколько SELECT FOR UPDATE тяжелее/хуже бенчмаркает чем SELECT? -- . ''`. Dmitry E. Oboukhov <unera@debian.org> : :’ : `. `~’ GPG key: 4096R/08EEA756 2014-08-30 `- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756
Вложения
Важный момент, который в CTE постгресовых всегда надо держать в уме:
The sub-statements in
WITH
are executed concurrently with each other and with the main query. Therefore, when using data-modifying statements in WITH
, the order in which the specified updates actually happen is unpredictable.В описываемом примере вообще не понятно, зачем делать select ... for update, сам обычный update что, не поставит нужный лок на строку?
2018-04-13 0:45 GMT-07:00 Dmitry E. Oboukhov <unera@debian.org>:
а можно ли применять SELECT FOR UPDATE в составных запросах?
то есть транзакцию не объявляем/начинаем, а пишем однократный
автокоммит-запрос, нечто вроде:
WITH
"s1" AS ( -- тут блокируемся
SELECT
*
FROM
"t"
WHERE
id = $1
FOR UPDATE
),
"v1" AS ( -- тут вычисляем значение
SELECT
SUM("v") AS "v"
FROM
"t2"
WHERE
"bla" = $2
)
UPDATE -- а дальше собственно update
"t"
SET
"v" = (SELECT v FROM v1)
FROM
"s1"
WHERE
"t"."id" = "s1"."id"
--
. ''`. Dmitry E. Oboukhov <unera@debian.org>
: :’ :
`. `~’ GPG key: 4096R/08EEA756 2014-08-30 `- 71ED ACFC 6801 0DD9 1AD1 9B86 8D1F 969A 08EE A756