Mysql Deadlock. Такой запрос может вызывать блокировку?

beba

Новичок
Здравствуйте.

Есть запрос:
Код:
update Таблица1 set Поле1 = (Поле1 + 1.00), Поле2 = (Поле2 - 1.00) where user_id = 281
может ли такой запрос вызывать блокировку, если запросов может быть много, и выполнятся могут не последовательно, а параллельно.

На данный момент запрос используется в апи, при обновлении баланса клиента. Когда один клиент начинает валить запросами в течении нескольких минут, появляется ошибка Deadlock.
Вот что в момент ошибки выдает INNODB MONITOR OUTPUT.

Код:
LOCK WAIT 4 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 2586457, OS thread handle 0x7f58fe4b1700, query id 372940204 127.0.0.1 usr_assistent Updating
ЗАПРОС, КОТОРЫЙ ВЫШЕ
В активных тразакциях я нигде больше не вижу использования этой таблицы.
Может ли этот запрос вызывать блокировку?
В коде в этой транзакции такие запросы:
Код:
update Таблица2 set is_calc = 1 where bsr_id = ИД
update Таблица1 set Поле1 = (Поле1 + 1.00), Поле2 = (Поле2 - 1.00) where user_id = ИДЮЗЕРА
insert into Таблица 3 (Поле3,Поле4, Поле5) values (Значение3, Значение4, Значение 5)
Может есть какие то идеи, заранее спасибо.
 

beba

Новичок
Код:
mysql> show variables like '%lock%';
+-----------------------------------------+----------------------+
| Variable_name                          | Value                |
+-----------------------------------------+----------------------+
| innodb_autoinc_lock_mode                | 1                    |
| innodb_lock_wait_timeout                | 50                  |
| innodb_locks_unsafe_for_binlog          | OFF                  |
| innodb_old_blocks_pct                  | 37                  |
| innodb_old_blocks_time                  | 0                    |
| innodb_print_all_deadlocks              | OFF                  |
| innodb_table_locks                      | ON                  |
| key_cache_block_size                    | 1024                |
| lock_wait_timeout                      | 31536000            |
| locked_in_memory                        | OFF                  |
| max_write_lock_count                    | 18446744073709551615 |
| metadata_locks_cache_size              | 1024                |
| performance_schema_max_rwlock_classes  | 30                  |
| performance_schema_max_rwlock_instances | 1000000              |
| query_alloc_block_size                  | 8192                |
| query_cache_wlock_invalidate            | OFF                  |
| range_alloc_block_size                  | 4096                |
| skip_external_locking                  | ON                  |
| transaction_alloc_block_size            | 8192                |
+-----------------------------------------+----------------------+
19 rows in set (0.02 sec)
 

beba

Новичок
я так понимаю мне может помочь эта опция:
innodb_locks_unsafe_for_binlog = ON
?

когда появились deadlock то я убрал в некоторых местах select из транзакции, были запросы типа insert into (select). И если у меня внутри транзакций нет селектов, то это должно помочь мне?
 

artoodetoo

великий и ужасный
если взаимные зависимости разомкнуть, то не будет и дедлоков.

КО
 

artoodetoo

великий и ужасный
дедлок возникает когда процесс А ждет результата процесса Б, а тот в свою ждет А. возможны и более длинные цепочки :D но всегда замкнутые.
уберите одну из зависимостей чтобы разомкнуть круг.

когда появились deadlock то я убрал в некоторых местах select из транзакции, были запросы типа insert into (select). И если у меня внутри транзакций нет селектов, то это должно помочь мне?
очень может быть.
 

beba

Новичок
проект не мной делался, и не на пару сотен строчек. В БД записей в некоторых таблицах за 16 млн.
я пытаюсь найти места, которые делают блокировку, но вот не получается все найти.
выполняю SHOW ENGINE INNODB STATUS;
(я описывал выше), никаких рядом транзакций затрагивающих эту таблицу не вижу. По поводу ключей, предыдущая ссылка. Хороший вариант, но ключ в этой таблице лишь один, первичный.
Как можно еще попытаться найти, какой запрос инициирует взаимоблокировку?
 
Последнее редактирование:

artoodetoo

великий и ужасный
У меня нет конкретного ответа, к сожалению. SHOW ENGINE INNODB STATUS может быть недостаточно для вычисления что с чем собачится.
Я бы пробовал перекраивать запросы так, чтобы они использовали другие индексы. И, если логика приложения позволяет, делать повторные попытки при ошибке.
 

Latik

Новичок
Была недавно похожая ситуация – простой select вызывал дедлок.
Дальнейшее разбирательство прояснило, что «разработчик» не поставил нужные индексы и когда база разрослась до 8М строк, селекты приводили к таким тормозам, что грубо говоря пока первый выполняется уже приходит повторный запрос.
В логах PostgreSQL жаловался:
Код:
2013-12-11 13:47:08 EET ERROR:  deadlock detected
2013-12-11 13:47:08 EET DETAIL:  Process 1273 waits for ShareLock on transaction 1969294500; blocked by process 1255.
        Process 1255 waits for ShareLock on transaction 1969294504; blocked by process 1273.
        Process 1273: SELECT * FROM acct_alive_query('29348', 13445194, 635337898, '192.168.0.187', '172.16.3.37', '00004810')
        Process 1255: SELECT * FROM acct_alive_query('29348', 13445194, 635337898, '192.168.0.187', '172.16.3.37', '00004810')
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
Была недавно похожая ситуация – простой select вызывал дедлок.
Простой select в Postgres'е блокирует только команды ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER и VACUUM FULL, а процитированный ShareLock накладывается только командой CREATE INDEX (автоматически), либо руками через LOCK TABLE. Т.е. где-то там у вас ещё и явные блокировки зачем-то прописаны.
 

Sad Spirit

мизантроп (Старожил PHPClub)
Команда форума
@Sad Spirit, не всё так просто :
> ... The fact that transaction waits are implemented as ShareLocks is an internal implementation...
http://www.postgresql.org/message-id/CAMkU=1w4TfWK-O6TZ-P6Mzic9=1_W_MRxtbhaHWR3M_zcHN3rQ@mail.gmail.com
О, век живи, век учись...

Но в любом случае, у вас там не SELECT дедлоки вызывает, где-то что-то внутрях acct_alive_query() в базу пишет.
 
Сверху