Обсуждение: SELECT FOR UPDATE без транзакции

Поиск
Список
Период
Сортировка

SELECT FOR UPDATE без транзакции

От
"Dmitry E. Oboukhov"
Дата:
а можно ли применять 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

Вложения

Re: SELECT FOR UPDATE без транзакции

От
Sergei Kornilov
Дата:
Привет
Вы в принципе не можете сделать select вне транзакции. Если вы делаете запрос вне транзакции - этот запрос будет
обёрнутв отдельную транзакцию автоматически.
 

Не представляю зачем в вашем примере мог быть нужен s1 вообще - но да, так брать блокировку возможно.

С уважением, Сергей


Re: SELECT FOR UPDATE без транзакции

От
"Dmitry E. Oboukhov"
Дата:
> Привет
> Вы в принципе не можете сделать 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

Вложения

Re: SELECT FOR UPDATE без транзакции

От
Timon
Дата:
>2. записываем новую запись t2
>3. аггрегатором вычисляем по t2 значение
важно понимать что на шаге 3 вы не увидите записи вставленные на шаге 2

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

Re: SELECT FOR UPDATE без транзакции

От
"Dmitry E. Oboukhov"
Дата:
>> 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

Вложения

Re: SELECT FOR UPDATE без транзакции

От
Nikolay Samokhvalov
Дата:
Важный момент, который в 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