Неблокирующие выборки в MySQL

Материал из Eludia.

Перейти к: навигация, поиск

Как известно (или, во всяком случае, всегда следует иметь в виду), за скорость элементарных операций, которой славится классический MySQL, приходится платить ощутимыми неудобствами, проявляющимися в многопользовательском режиме.

Самый яркий тому пример: на время исполнения любого SELECT все входящие в него MyISAM-таблицы целиком блокируются на запись. В частности, любой запрос, связанный с полным проходом по таблице log, подвешивает на время своего исполнения все действия активных пользователей. При использовании InnoDB и прочих storage backend'ов с блокировкой на уровне записей данная проблема стоит не столь остро, однако простор для оптимизации всё же остаётся.

А именно, при работе с большими (миллионными) таблицами всегда стоит иметь в виду местную MySQL'скую альтернативу SELECT: HANDLER. Эта инструкция позволяет заглядывать в таблицу напрямую, без каких-либо блокировок и буферизации. При этом нельзя использовать JOIN и естественным образом возникает риск получить неконсистентные данные, однако в ряде ситуаций эти ограничения вполне окупаются.

Типичный пример тому: проход всё той же таблицы log для восстановления данных, связанных с некоторыми событиями. Пример из жизни: вы добавили к таблице deps поле id_log_create и хотите, чтобы для всех ранее введённых строк deps этот указатель был установлен на запись log, соответствующую созданию записи. Задача решается скриптом

sql_do ('HANDLER log OPEN');

while (1) {

	my $log = sql_select_hash ("handler log read NEXT WHERE type='deps' AND action='create'");
	
	$log -> {id} or last;
	
	sql_do ('UPDATE deps SET id_log_create = ? WHERE id = ?', $log -> {id}, $log -> {id_object});

}

sql_do ('HANDLER log CLOSE');

который можно спокойно запускать в разгар рабочего дня: он никому не помешает.

Личные инструменты
Консультации
Разработчику
Администратору