The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

форумы  помощь  поиск  регистрация  майллист  вход/выход  слежка  RSS
"PostgreSQL - блокировка таблиц"
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [ Отслеживать ]

"PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 25-Авг-08, 18:06 
Hello, world!

Имеется таблица, упрощенный вид которой выглядит следующим образом:
    serial  _id       - ID объекта
    boolean _status   - Статус объекта (true - используется, false - не используется)
    *       _object   - Данные объекта.

При подключении нового пользователя ему, на время работы, должен выделятся один из объектов. Сейчас это реализовано как 'SELECT _id ... WHERE _status=FALSE LIMIT 1;' -> 'UPDATE ... SET _status=TRUE WHERE _id=$i;'. Это бажная схема - она будет некорректно работать при одновременных запросах. Возможно ли как-то в один акт получить _id незанятого объекта и заблокировать его, так, чтобы конкурирующие запросы не мешали друг-другу? ПС. PostgreSQL 8.3.3.

Высказать мнение | Ответить | Правка | Cообщить модератору

 Оглавление

Сообщения по теме [Сортировка по времени | RSS]


1. "PostgreSQL - блокировка таблиц"  
Сообщение от chip email(ok) on 25-Авг-08, 18:24 
UPDATE ... SET _status=TRUE WHERE _id=(SELECT _id ... WHERE _status=FALSE LIMIT 1);

>[оверквотинг удален]
>
>Имеется таблица, упрощенный вид которой выглядит следующим образом:
>    serial  _id      
> - ID объекта
>    boolean _status   - Статус объекта (true
>- используется, false - не используется)
>    *       _object
>  - Данные объекта.
>
>При подключении нового пользователя ему, на время работы, должен выделятся один из объектов. Сейчас это реализовано как 'SELECT _id ... WHERE _status=FALSE LIMIT 1;' -> 'UPDATE ... SET _status=TRUE WHERE _id=$i;'. Это бажная схема - она будет некорректно работать при одновременных запросах. Возможно ли как-то в один акт получить _id незанятого объекта и заблокировать его, так, чтобы конкурирующие запросы не мешали друг-другу? ПС. PostgreSQL 8.3.3.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

3. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 25-Авг-08, 18:48 
А _id заблокированного объекта теперь как получить?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

4. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 25-Авг-08, 22:52 
>UPDATE ... SET _status=TRUE WHERE _id=(SELECT _id ... WHERE _status=FALSE LIMIT 1);

Это та же самая бажная схема. Если 2 запроса начнут выполнятся одновременно, они выдадут 1 объект 2 раза.

Правильный вариант блокировать таблицу целиком или только строки выборки SELECT FOR UPDATE.

UPDATE RETURNING - позволяет и обновить и получить результат обновления.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

5. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 25-Авг-08, 23:27 
Почитал про "SELECT FOR UPDATE" - не до конца разрбрался:
    1) Нужно ли select и update делать в одной транзакцией? Можно привести пример (смотрел в гугле - все ссылки ведут на проблемы с savepoint при выполнении select for update - примеров пользования нет)?
    2) Предположим, что заблокированная страка ожидает апдейта, - будет ли она выбираться при параллельном селекте?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

6. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 25-Авг-08, 23:55 
Всё, разобрался экспериментальным путем - делать нужно в одной транзакции и таблица блокируется полностью до завершения транзакции. Блокировка таблицы - как-то не кашерно и может стать узким местом. Черт, неужели нет способа, чтобы не блокировать таблицу полностью?
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

7. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 26-Авг-08, 00:12 
>таблица
>блокируется полностью до завершения транзакции.

Не правда, блокируются только строки из условия where до конца транзакции. если используется select for update. Хотя возможно блокировка целой таблицы будет лучше ))


>Блокировка таблицы - как-то не кашерно
>и может стать узким местом. Черт, неужели нет способа, чтобы не
>блокировать таблицу полностью?

Вот именно, ты сериализуешь запросы, убивая параллельльность. Это и есть способ решения твоей проблемы с параллельностью ;)


Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

9. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 26-Авг-08, 00:45 
>
>Не правда, блокируются только строки из условия where до конца транзакции. если
>используется select for update. Хотя возможно блокировка целой таблицы будет лучше
>))
>

Я проверял - открыл две консоли - в одной набрал:
begin;
select t1 from test where t2=false for update;

Потом во второй повторил ввод - на чем консоль повисла, и отвисала только по завершению транзакции в первой консоли.

> Вот именно, ты сериализуешь запросы, убивая параллельльность. Это и есть способ решения твоей проблемы с параллельностью ;)

Гы :) ничего не понял, можно поподробней! :)

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

13. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 26-Авг-08, 15:31 
>Я проверял - открыл две консоли - в одной набрал:
>begin;
>select t1 from test where t2=false for update;
>
>Потом во второй повторил ввод - на чем консоль повисла, и отвисала...

блокируются только строки из условия where до конца транзакции. Ты блокировал одни и те же строки (одно условие where). Так и должно быть.

>> Вот именно, ты сериализуешь запросы, убивая параллельльность. Это и есть способ решения твоей проблемы с параллельностью ;)
>
>Гы :) ничего не понял, можно поподробней! :)

Ты хочешь параллельно (конкурентно) раздавать id? Это не возможно. Блокирока, гаранирующая последовательное выполнение выдачи id будет иначе будет выдача одного id двум. Можно сделать её явной, можно неявной.

минимум блокировок (ожидания) -  это открыть курсор со свободными id (не все, хватит 100 штук вполне) пытатся занять (update) их по одному. В большинстве случаев это будет первый полученный (fetch) id, редко второй и совсем редко дальнейшие.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

8. "PostgreSQL - блокировка таблиц"  
Сообщение от angra (ok) on 26-Авг-08, 00:28 
Например сначала делаем select но без limit
дальше для каждого id пытаемся сделать UPDATE ... SET _status=TRUE WHERE _id=$i and _status=FALSE
Если обновление успешно, то именно этот id используем в дальнейшем.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

10. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 26-Авг-08, 00:52 
;) действительно классно, но есть одно - база ~ 340Гб. К сожалению раньше не встречались задачи выходившие за пределы select/update/insert, а уважение к постгре большое. :) Поэтому хочется расковырять эту тему и найти родное (как надо) решение для постгри.
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

11. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 26-Авг-08, 15:13 
>;) действительно классно, но есть одно - база ~ 340Гб.

Это не важно.

Можно сделать так.
UPDATE ... SET _status=TRUE WHERE _status=FALSE and _id= (select _id from ... limit 1)

Но этот запрос может не сработать и тогда его надо повторять пока не сработает и пока есть свободные _id ;)

А можно открыть курсор и по одному перебирать fetch пока не получится сменить status.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

12. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 26-Авг-08, 15:28 
А как-же предыдущий ответ?:
>UPDATE ... SET _status=TRUE WHERE _id=(SELECT _id ... WHERE _status=FALSE LIMIT 1);

Это та же самая бажная схема. Если 2 запроса начнут выполнятся одновременно, они выдадут 1 объект 2 раза.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

14. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 26-Авг-08, 15:34 
>А как-же предыдущий ответ?:
>Это та же самая бажная схема. Если 2 запроса начнут выполнятся одновременно,
>они выдадут 1 объект 2 раза.

where _id=(select...)  !!!AND!!! _status=False


Если её уже заблокировали, второе условие не даст это сделать ещё раз. Будет 0 rows updated.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

15. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 26-Авг-08, 16:38 
В итоге получил:
UPDATE test SET t2=true WHERE t2=false AND t1=(SELECT t1 FROM test WHERE t2=false LIMIT 1) RETURNING t1;


Все правильно? ))

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

16. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 27-Авг-08, 01:34 
>В итоге получил:
>UPDATE test SET t2=true WHERE t2=false AND t1=(SELECT t1 FROM test WHERE
>t2=false LIMIT 1) RETURNING t1;
>
>
>Все правильно? ))

Если обработаешь вариант когда этот запрос ничего тебе не вернёт - то правильно.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

17. "PostgreSQL - блокировка таблиц"  
Сообщение от parad (??) on 27-Авг-08, 15:16 
Почему не вернет?: '... RETURNING t1;'
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

18. "PostgreSQL - блокировка таблиц"  
Сообщение от Аноним (??) on 27-Авг-08, 20:35 
>Почему не вернет?

Потому что сначала работает select, а потом update. И между ними статус может поменятся.

Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

2. "PostgreSQL - блокировка таблиц"  
Сообщение от Vladimir (??) on 25-Авг-08, 18:41 
BEGIN
LOCK TABLE ... IN ACCESS EXCLUSIVE MODE
SELECT _id ... WHERE _status=FALSE LIMIT 1
UPDATE ... SET _status=TRUE WHERE _id=$i
COMMIT
Высказать мнение | Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Оцените тред (1=ужас, 5=супер)? [ 1 | 2 | 3 | 4 | 5 ] [Рекомендовать для помещения в FAQ]




Спонсоры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2022 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру