MySQL - обновление строк таблицы без блокировки строк - PullRequest
2 голосов
/ 19 апреля 2019

У меня есть требование, когда нам нужно обновить строку, не удерживая блокировку во время обновления.

Вот подробности требований, мы будем запускать пакетную обработку для таблицы каждые 5 минут update blogs set is_visible=1 where some conditions этот запрос выполняется для миллионов записей, поэтому мы не хотим блокировать все строки для записи во время обновлений.

Я полностью понимаю последствия отсутствия блокировок записи, что хорошо для нас, потому что is_visibleстолбец будет обновляться только этим пакетным процессом, другой поток не будет обновлять этот столбец.С другой стороны, будет много обновлений для других столбцов той же таблицы, которые мы не хотим блокировать

Ответы [ 2 ]

0 голосов
/ 19 апреля 2019

Прежде всего, если вы по умолчанию используете механизм хранения InnoDB MySQL, вы не сможете обновить данные без блокировок строк, кроме как установить уровень изоляции транзакции READ UNCOMMITTED, запустив

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

Однако я не думаю, что поведение базы данных - это то, что вы ожидаете, поскольку в этом случае разрешено грязное чтение. READ UNCOMMITTED редко используется на практике.

Чтобы дополнить ответ от @Tim, действительно неплохо иметь уникальный индекс для столбца, используемого в предложении where. Тем не менее, обратите внимание, что нет абсолютной гарантии, что оптимизатор в конечном итоге выберет такой план выполнения, используя созданный индекс. Это может работать или не работать, в зависимости от случая.

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

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

P.S. Блокировка IX не для самой записи, а для объекта таблицы с более высокой гранулярностью. И даже при уровне изоляции транзакции REPEATABLE READ блокировка пробела не выполняется, когда запрос использует уникальный индекс.

0 голосов
/ 19 апреля 2019

Рекомендуется всегда получать определенную блокировку, когда есть вероятность, что обновление может произойти одновременно с другими транзакциями.Если в качестве механизма хранения используется MyISAM, MySQL во время обновления заблокирует всю таблицу, и с этим ничего не поделаешь.Если механизм хранения будет InnoDB, то возможно, что MySQL установит только эксклюзивную блокировку IX для записей, на которые нацелено обновление, но есть предостережения в этом случае.Первое, что вы должны сделать, чтобы попытаться достичь этого, было бы SELECT ... FOR UPDATE:

SELECT * FROM blogs WHERE <some conditions> FOR UPDATE;

Чтобы InnoDB блокировал только обновляемые записи, для столбца должен быть уникальный индекскоторый появляется в предложении WHERE.В случае вашего запроса, предполагая, что id был задействован столбец, это должен быть первичный ключ, иначе вам потребуется создать уникальный индекс:

CREATE UNIQUE INDEX idx ON blogs (id);

Даже с таким индексомInnoDB все еще может применять блокировки gap к записям между значениями индекса, чтобы обеспечить соблюдение контракта REPEATABLE READ.

Таким образом, вы можете добавить индекс для столбца (-ов).) участвует в предложении WHERE для оптимизации обновления InnoDB.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...