Существует ли ограничение на блокировку строк в MySQL 5.7?

#mysql #mysql-5.7 #pessimistic-locking

Вопрос:

Я столкнулся с проблемой в MySQL 5.7, когда я выбираю 14 или более строк ДЛЯ ОБНОВЛЕНИЯ, вся таблица блокируется. Даже несмотря на то, что я выбираю их по первичному ключу (так что он индексирован и уникален). Буквально это выглядит так. Когда я выполняю этот запрос:

 select * from mytable
where id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)
for update;
 

Все работает нормально, и заблокированы только выбранные строки. Но этот запрос:

 select * from mytable
where id in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)
for update;
 

блокирует весь стол. Я не могу обновить ни одну другую запись, ни вставить новую строку. Стол заперт. Идентификаторы могут быть разными, важно их количество (14 или более). Я попытался поискать его в Google, но ничего не нашел.

Является ли это каким-то строгим ограничением MySQL (мы используем версию 5.7) для блокировки строк (13 строк), и если вы выберете больше, то будет применена блокировка таблицы? Можно ли это как-то изменить? Или это только наша конкретная проблема, и нам нужно копнуть глубже?

Комментарии:

1.И если вы попытаетесь заблокировать зазор, например : select * from mytable where id between 1 and 20 for update ? Блокирует ли он весь стол ? Или удаление * select id from mytable where id between 1 and 20 for update

2. @basha04 хммм… Я попробовал и получил интересные результаты. Если я использую МЕЖДУ ними, он блокирует только выбранные строки, по крайней мере, до 60 результатов (больше не пробовал), что многообещающе, но не решает проблему, так как мне нужны произвольные идентификаторы. Что касается select id того, что вместо select * того, чтобы он работал без блокировки только для 11 строк, на 12-й он блокирует таблицу. Таким образом, это еще меньше, чем при использовании *

Ответ №1:

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

 CREATE TEMPORARY TABLE if not exists tmp (id int primary key);
truncate tmp;
INSERT INTO tmp VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15);
select t.* from mytable t
join tmp on tmp.id = t.id
for update;
 

Таким образом, все работает гладко, и только указанные строки блокируются независимо от того, сколько идентификаторов мы передаем. Однако есть некоторые проблемы.

Во-первых, если бы мы использовали engine=memory этот трюк, он по какой-то причине не сработал. Также, если мы вставили значения во временную таблицу, используя select вместо values дополнительной select for update все еще заблокированной целой таблицы определенное количество идентификаторов. Но в последнем случае проблему можно было решить, позвонив optimize table tmp; сразу после вставки (когда мы ее использовали engine=memory , это все равно не помогло).

Итак, вот оно что. Надеюсь, это кому-нибудь поможет.