Пост под пивом, поэтому в тексте много лишнего. Суть в том, что мне очень не нравится то, как происходят постоянные затыки при апдейте базы mySQL с механизмом MyISAM. Что-поделаешь, система такая... Всегда приходится чем-то жертвовать ради чего-то другого... Короче, после долгих и почти бесполезных оптимизаций, отдельно себе отметил я поля статистики в постоянно-читаемых таблицах, которые вроде бы и тоже полезно обновлять, но не критично их немедленное обновление. Вот там бы и пригодился UPDATE DELAYED, который, увы, нереален в MyISAM. Чтобы не заставлять пользователя ждать, проще написать функцию, которая просто суёт «запрос обновления» в некую промежуточную табличку (без ожидания немедленного обновления, разумеется, ни конечной, ни промежуточной таблицы. Всегда INSERT DELAYED делаем, короче...). Да, так вот, суём все наши зарержанные обновления в промежуточную таблицу, а затем пишем crontab, который подхватывает ожидаемые обновления и выполняет их потихоньку, раз в несколько минут, например. Чуть позже я приведу примеры PHP-функции mysql_delayed_update(), а также PHP-скрипта для вешания на кронтаб...
Реализация: - Создаём mySQL табличку «delayed_updates». С одним полем: query (TEXT), которое содержит собственно текст mySQL-запроса.
(Можно было бы как-то ещё сделать так, чтобы отсеивать запросы, которые стали уже неактуальными ко времени их выполнения, может будет реализовано в следующей «версии».)
- Пишем функцию (внимание! этот блог портит PHP-код, переделывая кавычки в ёлочки и апострофы. Я знаю об этом, но пока ничего менять не хочу. Это не программерская блог-платформа.):
function mysql_delayed_update($q) {
mysql_query(’INSERT DELAYED INTO delayed_updates (query) VALUES («’.mysql_real_escape_string($q).’»)’);
}
- Пишем кронтаб. На какое время он будет вешаться — особого значения нет. Я вызываю его раз в 10 минут и считаю это нормальным:
<?
// Подключаемся к базе
include(dirname(dirname(__FILE__)).’/public_html/inc/mysql.php’);
function my_microtime() {
$t = explode(’ ’, microtime());
return $t[1]+$t[0];
}
$mtime = my_microtime();
mysql_query(’CREATE TEMPORARY TABLE tmp_delayed_updates (query text NOT NULL)’);
mysql_query(’LOCK TABLES delayed_updates WRITE’);
mysql_query(’INSERT INTO tmp_delayed_updates (SELECT query FROM delayed_updates)’);
mysql_query(’TRUNCATE TABLE delayed_updates’);
mysql_query(’UNLOCK TABLES’);
if ($r = mysql_query(’SELECT query FROM tmp_delayed_updates’)) {
while ($row = mysql_fetch_row($r))
mysql_query($row[0]);
mysql_free_result($r);
}
print ’DONE. Checked ’.mysql_affected_rows().’ log records. Generated in ’.sprintf(’%.3f’, (my_microtime() – $mtime))." seconds.\n»;
?>
P.S. Вещь оказалась на первое время полезной и даже использовалась, однако, впоследствии было решено было отказаться от этого в пользу более корректных (элегантных) методов оптимизации. Это было отказ конкретно от «низкоуровневых» delayed updat’ов, но не от идеи в целом. Сама идея применяется, но на более высоком уровне, для проведения целой серии операций. Запрос-флаг обновления заказывается с помощью INSERT DELAYED. |