Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Deadlock при добавлении строки / 25 сообщений из 42, страница 1 из 2
25.12.2013, 12:38:10
    #38511967
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Здравствуйте.

Есть такая задача: пополнение баланса пользователя.

По запросу на пополнение баланса выполняется простой алгоритм: Ищем в таблице балансов запись, которая принадлежит пользователю. Если у пользователя есть баланс, то такая запись присутствует, если баланса нет - записи тоже нет.
Если приходит одновременно несколько запросов на пополнение баланса одному юзеру, у которого нет записи (нулевой баланс), то случается deadlock.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
START TRANSACTION;
SELECT * FROM `balances` WHERE id=1 FOR UPDATE;
...
// если существует запись, делается UPDATE - с этим проблем нет, т.к. существующая запись блокируется SELECT-ом в начале транзакции
UPDATE `balances` SET `balance` = `balance`+10 WHERE `id` = 1;

// если записи нет,  делается INSERT - вот тут появляется deadlock, если до этого момента началась вторая транзакция, т.к. SELECT в начале транзакции ничего не заблокировал
INSERT INTO `balances` (`id`, `balance`) VALUES (1, 10.00);

COMMMIT;



id - не является автоинкрементом, на самом деле это USER_ID

Пробовал INSERT ... ON ON DUPLICATE KEY UPDATE - также не решает проблемы.

Как решить проблему?
...
Рейтинг: 0 / 0
25.12.2013, 13:16:45
    #38512036
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Oleg8000,

Дай определение таблицы balances.
В частности, интересно какие там индексы и какой движок используется. (storage engine).
...
Рейтинг: 0 / 0
25.12.2013, 13:18:02
    #38512039
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Oleg8000
Код: sql
1.
если существует запись, делается UPDATE - с этим проблем нет, т.к. существующая запись блокируется SELECT-ом в начале транзакции

Решение напрашивается само собой - сразу создавать для нового пользователя запись с нулевым балансом.
...
Рейтинг: 0 / 0
25.12.2013, 13:37:35
    #38512077
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZiv,
Код: sql
1.
2.
3.
4.
5.
CREATE TABLE IF NOT EXISTS `balances` (
  `id` int(1) NOT NULL,
  `balance` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
...
Рейтинг: 0 / 0
25.12.2013, 13:40:11
    #38512080
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
tanglirРешение напрашивается само собой - сразу создавать для нового пользователя запись с нулевым балансом.
Не хотелось бы... юзеров будет очень много, поэтому решили вынести баланс в отдельную таблицу, чтобы работа с балансом была максимально быстрой
...
Рейтинг: 0 / 0
25.12.2013, 13:41:32
    #38512084
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Oleg8000MasterZiv,
Код: sql
1.
2.
3.
4.
5.
CREATE TABLE IF NOT EXISTS `balances` (
  `id` int(1) NOT NULL,
  `balance` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;




Так просто ? Два поля ? Не верю...
...
Рейтинг: 0 / 0
25.12.2013, 13:42:24
    #38512085
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Oleg8000tanglirРешение напрашивается само собой - сразу создавать для нового пользователя запись с нулевым балансом.
Не хотелось бы... юзеров будет очень много, поэтому решили вынести баланс в отдельную таблицу, чтобы работа с балансом была максимально быстрой

Это дурость.

Не в смысле вынесения, а в смысле надежды, что станет быстрее.
...
Рейтинг: 0 / 0
25.12.2013, 13:45:07
    #38512091
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZivТак просто ? Два поля ? Не верю...Вытащили 2 поля из основной таблицы юзеров в отдельную. Видимо, во многих полях в исходной таблице был нулл/0, и надеялись, что за счёт отсутствия их в новой таблице работа ускорится. Но
MasterZivЭто дурость.

Не в смысле вынесения, а в смысле надежды, что станет быстрее.
...
Рейтинг: 0 / 0
25.12.2013, 13:48:56
    #38512100
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
тут еще интереснее стало...
даже если приходят запрос на пополнение баланса от разных юзеров. все равно вываливается deadlock

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
transaction 1> start transaction;
Query OK, 0 rows affected (0.00 sec)

transaction 1> select * from balances where id=5 for update;
Empty set (0.00 sec)


transaction 2> start transaction;
Query OK, 0 rows affected (0.00 sec)

transaction 2> select * from balances where id=10 for update;
Empty set (0.01 sec)

transaction 2> insert into balances (id, balance) values (10,10);
// висит ...

transaction 1> insert into balances (id, balance) values (5,5);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

// вторая транзакция после делока первой, выполнилась
Query OK, 1 row affected (9.14 sec)



Мне кажется, это связано с блокировкой следующего ключа, но пока я плаваю в этой теме... В эту сторону копать?
...
Рейтинг: 0 / 0
25.12.2013, 13:50:49
    #38512104
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZiv,
ну это просто для того чтоб легче примеры читались.
ситуация воспроизводится при такой структуре.
...
Рейтинг: 0 / 0
25.12.2013, 13:51:29
    #38512106
miksoft
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
tanglirсразу создавать для нового пользователя запись с нулевым балансом.+1
...
Рейтинг: 0 / 0
25.12.2013, 13:55:31
    #38512115
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Давайте рассмотрим эту проблему не с точки зрения архитектуры, а с точки зрения решения самой проблемы.
Структура таблицы есть. Воспроизвести проблему на локале - дело 1 минуты, достаточно открыть 2 терминала.
Deadlock есть. Как от него избавится?
...
Рейтинг: 0 / 0
25.12.2013, 13:58:20
    #38512122
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Ну или ужесточите уровень изоляции.
...
Рейтинг: 0 / 0
25.12.2013, 14:05:53
    #38512135
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Akina,
вот кстати копаю в этом направлении ))
только не ужесточить, а наоборот понизить помогло.

Код: sql
1.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;



тогда такой запрос работает как надо.

Код: sql
1.
insert into balances (id, balance) values (1,10) ON DUPLICATE KEY UPDATE balance = balance+10;



но это еще только первые вести с полей... возможно будут побочные эффекты
...
Рейтинг: 0 / 0
25.12.2013, 14:51:50
    #38512188
Akina
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
А был какой?
...
Рейтинг: 0 / 0
25.12.2013, 15:10:51
    #38512206
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Oleg8000тут еще интереснее стало...
даже если приходят запрос на пополнение баланса от разных юзеров. все равно вываливается deadlock

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
transaction 1> start transaction;
Query OK, 0 rows affected (0.00 sec)

transaction 1> select * from balances where id=5 for update;
Empty set (0.00 sec)


transaction 2> start transaction;
Query OK, 0 rows affected (0.00 sec)

transaction 2> select * from balances where id=10 for update;
Empty set (0.01 sec)

transaction 2> insert into balances (id, balance) values (10,10);
// висит ...

transaction 1> insert into balances (id, balance) values (5,5);
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

// вторая транзакция после делока первой, выполнилась
Query OK, 1 row affected (9.14 sec)



Мне кажется, это связано с блокировкой следующего ключа, но пока я плаваю в этой теме... В эту сторону копать?


Странно, такого вроде бы быть не должно...
А точно между ними дедлок ?
попробуй только одну сессию пустить ...
...
Рейтинг: 0 / 0
25.12.2013, 15:11:25
    #38512207
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
AkinaНу или ужесточите уровень изоляции.

Куда уж жёсче ...
Некуда ужесточать...
...
Рейтинг: 0 / 0
25.12.2013, 15:13:06
    #38512213
MasterZiv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
Можно попробовать не делать SELECT... FOR UPDATE вообще,
делать UPDATE, что-то про UPDATE-илось -- ок, хорошо, нет -- вставлять.
...
Рейтинг: 0 / 0
25.12.2013, 15:17:13
    #38512215
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
AkinaА был какой?
был по дефолту REPEATABLE-READ
...
Рейтинг: 0 / 0
25.12.2013, 15:18:39
    #38512218
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZivпопробуй только одну сессию пустить ...

по отдельности отрабатывают нормально
...
Рейтинг: 0 / 0
25.12.2013, 15:25:48
    #38512229
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZivМожно попробовать не делать SELECT... FOR UPDATE вообще,
делать UPDATE, что-то про UPDATE-илось -- ок, хорошо, нет -- вставлять.

Без FOR UPDATE нельзя.
Это редкий случай - когда пришел запрос, а баланса у юзера нету.
Чаще происходит ситуации, когда у юзера есть баланс.

Если в начале транзакции будет просто SELECT ... WHERE id=1, а в конце UPDATE ... SET balance = balance+10 WHERE id=1
То при паралельных запросах один из них потеряется
...
Рейтинг: 0 / 0
25.12.2013, 15:26:16
    #38512231
ScareCrow
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
insert on duplicate key update
...
Рейтинг: 0 / 0
25.12.2013, 15:28:25
    #38512234
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
ScareCrowinsert on duplicate key update
а еще можно прочесть все сообщения в теме.
уже обсуждалось....
...
Рейтинг: 0 / 0
25.12.2013, 15:31:50
    #38512240
Oleg8000
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
ScareCrowinsert on duplicate key update
На самом деле это пока наилучший вариант, но требуется понизить уровень изоляции.
Это пока смущает...
...
Рейтинг: 0 / 0
25.12.2013, 15:40:19
    #38512249
tanglir
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Deadlock при добавлении строки
MasterZivСтранно, такого вроде бы быть не должно...
А точно между ними дедлок ?я ради интереса на пустой таблице (создал по ddl ТСа) попробовал - воспроизводится
на пустой! таблице
что оно там ухитряется залочить?..
...
Рейтинг: 0 / 0
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Deadlock при добавлении строки / 25 сообщений из 42, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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