Изоляция транзакции при выборе, вставке, удалении - PullRequest
3 голосов
/ 06 апреля 2010

Что может пойти не так со следующей транзакцией, если она выполняется одновременными пользователями с уровнем изоляции по умолчанию READ COMMITTED?

BEGIN TRANSACTION

SELECT * FROM t WHERE pid = 10 and r between 40 and 60
-- ... this returns tid = 1, 3, 5
-- ... process returned data ...
DELETE FROM t WHERE tid in (1, 3, 5)
INSERT INTO t (tid, pid, r) VALUES (77, 10, 35)
INSERT INTO t (tid, pid, r) VALUES (78, 10, 37)
INSERT INTO t (tid, pid, r) VALUES (79, 10, 39)

COMMIT

Ответы [ 4 ]

3 голосов
/ 06 апреля 2010

У вас могут быть серьезные проблемы с производительностью из-за мертвых блокировок

SELECT получит общую блокировку на странице, а затем DELETE попытается обновить эти блокировки до эксклюзивных блокировок.

Если другой пользователь выполняет тот же запрос, он может получить общие блокировки на той же странице в то же время, что и другой пользователь. Затем, когда кто-то пытается перейти на эксклюзивную блокировку, он будет ожидать освобождения всех других общих блокировок. Другой также будет ожидать освобождения всех общих блокировок. Оба будут иметь общую блокировку и ожидают, пока другая освободит эту общую блокировку, чтобы сама могла получить эксклюзивную блокировку. Другие запросы будут накапливаться при попытке сделать то же самое, и вскоре начнут обнаруживаться взаимоблокировки, и запросы начнут отменяться и откатываться. В зависимости от частоты запросов обнаружение мертвой блокировки механизма БД может не убивать запросы так быстро, как приходят новые, то есть ни один из запросов не будет выполнен успешно.

Вам нужно будет добавить что-то вроде подсказки в select, чтобы запросить получение эксклюзивной блокировки с самого начала. Или вы можете переместить селектор за пределы транзакции и использовать обнаружение конфликта параллелизма в критериях где ваш другой оператор.

1 голос
/ 06 апреля 2010

Все это странно для меня. Какова цель выбора? Это ничего не дает. Напишите удаление, чтобы выбрать записи, которые вы хотите. Что поразило бы меня проблему одновременных пользователей, так это то, что они будут пытаться вставлять одни и те же записи, поскольку вы жестко закодировали значения и, таким образом, вероятно, столкнулись бы с уникальными ограничениями, которые вы, вероятно, имеете в tid или в комбинации tid, pid.

Честно говоря, что вы пытаетесь достичь здесь? Это похоже на специальный запрос, предназначенный для одноразового использования, который вы пытаетесь выполнить несколько раз. Почти всегда плохая идея так жестко программировать.

0 голосов
/ 06 апреля 2010

Вы не используете блокировку для SELECT, поэтому все получат одинаковые результаты, все увидят записи tid 1, 3 и 5. Все обработают эти записи, и все попытаются удалить эти записи. И это не сработает, операция удаления приведет к блокировке. Только одна транзакция может заблокировать эти записи, все остальные транзакции должны ждать принятия первой транзакции. Эта транзакция будет вставлять новые записи и фиксировать, все остальные ничего не будут удалять (не может найти записи, нет проблем), а также вставлять новые записи. Эти записи имеют одинаковые данные, это проблема?

Возможно, вы хотите, чтобы SELECT ... FROM ... FOR UPDATE; заблокировал записи, которые вы хотите обработать. http://www.postgresql.org/docs/8.4/interactive/sql-select.html

0 голосов
/ 06 апреля 2010

Вы действительно должны упомянуть, используете ли вы oracle или postgres. Кроме того, вы должны явно указать свою блокировку и не полагаться на поведение по умолчанию. Они могут изменяться вместе с другими базами данных или версиями баз данных.

...