powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Serializable Isolation versus True Serializability
8 сообщений из 8, страница 1 из 1
Serializable Isolation versus True Serializability
    #33040585
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Коллеги,

помогите, пожалуйста, придумать пример из какой-нибудь
общепонятной предметной области, иллюстрирующий
аномалию из

http://www.postgresql.org/docs/8.0/static/transaction-iso.html#MVCC-SERIALIZABILITY

Хочется вместо class и value что-нибудь более жизненное, берущее,
я бы сказал, за душу.

Есть похожий пример, где одна транзакция удаляет родителя, потому
что у него нет ребенка, а другая в это же время
убеждается в существовании родителя и создает к нему
ребенка - тут все просто, но хочется более похожего на постгресовский
пример, чтобы SELECT FOR UPDATE не помогал.

Спасибо.
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33042781
Funny_Falcon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пример: биллинг (упрощенно):
Для простоты не будет описываться через триггеры
и опустим вычисление цены звонка (только изменим стоимость минуты):

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
create table Phone
(
    id_phone int not null primary key,
    phone varchar( 30 ),
    time_from timestamptz,                -- время действия
    time_to timestamptz,                   -- телефона
    price float
);

create unique index ix_phone_phto on Phone (phone,time_to);

create table Call
(
    phone varchar( 30 ) not null,
    time_start timestamptz not null,
    time_stop timestamptz not null,
    id_phone int,
    price float,
    primary key (phone,time_start)
);
create index ix_call_phone on Call
(
    id_phone,
    time_start
);
create index ix_call_phone_1 on Call
(
    phone,
    time_start,
    (coalesce(id_phone,- 1 ))
) when (coalesce(id_phone,- 1 )=- 1 );
Заполним талицу Phone:
Код: plaintext
1.
2.
insert into Phone values ( 1 ,'2345678','2005-03-01','3000-01-01', 2 . 30 );
insert into Phone values ( 2 ,'7654321','2005-03-01','3000-01-01', 4 . 60 );
Пусть одновременно выполняются 2 транзакции (будем помечать точки во времени):
1-я:
Шеф дает указание: "Придурков с телефона '2345678' в этом месяце считать по 3.70!!! Ты не забыл?"
Вы понимаете, что забыли и выполняете (естественно с помощью пары кнопок на форме):
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
-- точка времени 2
begin;
update Phone set time_to='2005-04-01' where id_phone= 1 ;
insert into Phone values ( 3 ,'2345678','2005-04-01','3000-01-01', 3 . 70 );
-- вторая транзакция не завершилась, потому не считаем '2345678' по 3.70
update Call set id_phone= 3 , price= 3 . 70  where id_phone= 1  and time_start 
                between '2005-04-01'::timestamptz and '2005-05-01'::timestamptz;
-- точка времени 3
commit;

2-я транзакция вставляет телефоны и билингует их:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
-- точка времени 1
begin;
insert into Call (phone,time_start,time_stop) values ('2345678','2005-04-29 10:00:01','2005-04-29 10:01:29');
insert into Call (phone,time_start,time_stop) values ('7654321','2005-04-29 10:00:35','2005-04-29 10:02:15');
-- точка времени 2
-- первая транзакция не завершилась, потому считаем '2345678' по 2.30
update Call set id_phone=ph.id_phone ,price=ph.price from Phone ph where ph.phone = phone and time_start between time_from and time_to
and  coalesce(id_phone,- 1 )=- 1 ;
-- точка времени 3
commit;
Можем теперь сделать выборку и убедиться:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
select count(*)  as c from Call where id_phone= 3 ;
/*
   c
------
   0
*/
select phone,price from Call group by phone,price;
/*
 phone   |  m
--------+----
2345679 | 2.30
7654321 | 4.20
*/
При True Serializable такого не возникнет: либо первая трагзакция начинается
раньше и вторая считает как "3", либо вторая считает как "1", а первая
изменяет.
Самое интересное: при READ COMMITTED вероятность такого бага меньше:
завершись одна из транзакций до точки 2, вторая отработает правильно.
Можно разбить вторую на ввод данных и обсчет, но все равно : если первая
транзакция началась до commit ввода данных и завершилась после update
второй, ошибка будет.
Единтсвенный выход: использовать явный LOCK. Причем мое мнение:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
-- в первой транзакции :
begin; 
LOCK Phone,Call IN SHARE;
-- во второй :
begin;
LOCK Phone IN SHARE;
LOCK Call IN ROW SHARE;
Кто сможет обойтись без LOCK, прошу рассказать, буду признателен.
Только прошу протестить, что бы ни каких возможностей для данного глюка; я
этот пример (не в точности, но изоморфный) сног до головы перевертел.
SELECT FOR UPDATE не спасает (как мне кажется) - он не увидит еще не
вставленные строки, да и возвращать 2000 строк, уже тарифицированных в
этом месяце как "1" (по 2.30) - sucks.
Заранее признателен !!!
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33046496
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Funny_Falcon
Кто сможет обойтись без LOCK, прошу рассказать, буду признателен.
Только прошу протестить, что бы ни каких возможностей для данного глюка; я
этот пример (не в точности, но изоморфный) сног до головы перевертел.
SELECT FOR UPDATE не спасает (как мне кажется) - он не увидит еще не
вставленные строки, да и возвращать 2000 строк, уже тарифицированных в
этом месяце как "1" (по 2.30) - sucks.


Честно говоря, я не вижу здесь большой проблемы, и
SELECT FOR UPDATE вполне спасает.

Если транзакция 2 сделает SELECT FOR UPDATE записи из
таблицы CALL (я не понял про 2000 строк), то она будет
ждать завершения транзакции 1,
потому что интересующая (старая, с ID 1) запись
была изменена. После завершения транзакции 1, транзакция
2 будет завершена с сообщением
"ERROR: could not serialize access due to concurrent update",
после чего ее нужно выполнить заново.

В любом случае, пример очень интересный и дающий
пищу для размышлений.
Большое спасибо.
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33046513
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ilejnЕсли транзакция 2 сделает SELECT FOR UPDATE записи из
таблицы CALL (я не понял про 2000 строк),


Из таблицы Phone (а не СALL).
Но про 2000 строк я все равно не понял ;)
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33049841
Funny_Falcon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ilejnя не понял про 2000 строк
Это упрощенный кусок реальной системы биллинга, которую я пытаюсь проектировать :-)
ilejnПосле завершения транзакции 1, транзакция
2 будет завершена с сообщением
"ERROR: could not serialize access due to concurrent update",
после чего ее нужно выполнить заново.
Большое спасибо :-) И охота некоторым длинные транзакции откатывать :-)
Притом, неизвестно какая транзакция застопорится.
ilejnИз таблицы Phone (а не СALL).
Но про 2000 строк я все равно не понял ;)
В этом случае вроде как и не 2000, а 200 :-).

Хотя, над этим стоит подумать. Ты совет тестировал?
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33050545
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И охота некоторым длинные транзакции откатывать :-)


Охота, если необходимость отката транзакций возникает редко.
Неохота (иными словами, нужно использовать LOCK TABLE в начале транзакции) в противном случае.

Третий вариант (когда все отработало быстро , но неправильно) обычно не подходит, так что приходится выбирать из этих двух.

На самом деле, использовать в PostgreSQL ISOLATION LEVEL SERIALIZABLE есть извращение, но иногда от этого никуда не денешься.
И, кстати, не нужно делать транзакции длинными.


Хотя, над этим стоит подумать. Ты совет тестировал?


Буквально в таком виде не тестировал.
Ты в похожем случае употреблял красивое слово "изоморфный".
Так вот я тестировал изоморфный совет ;)
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33053453
КРЕД
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имхо какое-то тут гониво ...

Зачем выполнять транзакцию без операторов SELECT / SELECT FOR UPDATE ?

Если вы думаете что так будет быстрее то это ещо необязательно правильно !
автор
-- точка времени 2
begin;
SELECT id_phone into t .... for update
update Phone set time_to='2005-04-01' where id_phone=t;
insert into Phone values (3,'2345678','2005-04-01','3000-01-01',3.70);
-- вторая транзакция не завершилась, потому не считаем '2345678' по 3.70
update Call set id_phone=t, price=3.70 where id_phone=t and time_start
between '2005-04-01'::timestamptz and '2005-05-01'::timestamptz;
-- точка времени 3
commit;

автор-- точка времени 1
begin;
insert into Call (phone,time_start,time_stop) values ('2345678','2005-04-29 10:00:01','2005-04-29 10:01:29');
insert into Call (phone,time_start,time_stop) values ('7654321','2005-04-29 10:00:35','2005-04-29 10:02:15');
-- точка времени 2
-- первая транзакция не завершилась, потому считаем '2345678' по 2.30
-- а от куда берутся "phone" "time_from" "time_to" это рандомные значения ? тогда результят тоже будет рандомный ... или это ключи из Базы ? Тогда может их залочить сначала ?
update Call set id_phone=ph.id_phone ,price=ph.price from Phone ph where ph.phone = phone and time_start between time_from and time_to and coalesce(id_phone,-1)=-1;
-- а не проще это вынести в триггер?
-- точка времени 3
commit;

ЗЫ Блокировки в базе какраз и предназначены чтоб с их помощу выстраивать транзакции в очереди .
ЗЫ2 Используя "Serializable Isolation" данные нужно хотябы читать для начала .
...
Рейтинг: 0 / 0
Serializable Isolation versus True Serializability
    #33057047
ilejn
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
-- точка времени 2
begin;
SELECT id_phone into t .... for update
update Phone set time_to='2005-04-01' where id_phone=t;
insert into Phone values (3,'2345678','2005-04-01','3000-01-01',3.70);
-- вторая транзакция не завершилась, потому не считаем '2345678' по 3.70
update Call set id_phone=t, price=3.70 where id_phone=t and time_start
between '2005-04-01'::timestamptz and '2005-05-01'::timestamptz;
-- точка времени 3
commit;

Объясните, пожалуйста, что нового привносит SELECT FOR UPDATE, при условии, что та же запись блокируется предложением UPDATE?


а от куда берутся "phone" "time_from" "time_to" это рандомные значения ? тогда результят тоже будет рандомный ... или это ключи из Базы ? Тогда может их залочить сначала ?


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


ЗЫ2 Используя "Serializable Isolation" данные нужно хотябы читать для начала .

А на что это повлияет? Если можно, с примерами.

Спасибо.
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Serializable Isolation versus True Serializability
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]