Delayed UPDATE (будет обновляться)
  
Author:

Пост под пивом, поэтому в тексте много лишнего.

Суть в том, что мне очень не нравится то, как происходят постоянные затыки при апдейте базы mySQL с механизмом MyISAM. Что-поделаешь, система такая... Всегда приходится чем-то жертвовать ради чего-то другого...

Короче, после долгих и почти бесполезных оптимизаций, отдельно себе отметил я поля статистики в постоянно-читаемых таблицах, которые вроде бы и тоже полезно обновлять, но не критично их немедленное обновление. Вот там бы и пригодился UPDATE DELAYED, который, увы, нереален в MyISAM.

Чтобы не заставлять пользователя ждать, проще написать функцию, которая просто суёт «запрос обновления» в некую промежуточную табличку (без ожидания немедленного обновления, разумеется, ни конечной, ни промежуточной таблицы. Всегда INSERT DELAYED делаем, короче...).

Да, так вот, суём все наши зарержанные обновления в промежуточную таблицу, а затем пишем crontab, который подхватывает ожидаемые обновления и выполняет их потихоньку, раз в несколько минут, например.

Чуть позже я приведу примеры PHP-функции mysql_delayed_update(), а также PHP-скрипта для вешания на кронтаб...


Реализация:

  1. Создаём mySQL табличку «delayed_updates». С одним полем: query (TEXT), которое содержит собственно текст mySQL-запроса.
    (Можно было бы как-то ещё сделать так, чтобы отсеивать запросы, которые стали уже неактуальными ко времени их выполнения, может будет реализовано в следующей «версии».)
     
  2. Пишем функцию (внимание! этот блог портит PHP-код, переделывая кавычки в ёлочки и апострофы. Я знаю об этом, но пока ничего менять не хочу. Это не программерская блог-платформа.):
    function mysql_delayed_update($q) {
       mysql_query(’INSERT DELAYED INTO delayed_updates (query) VALUES («’.mysql_real_escape_string($q).’»)’);
    }
     
  3. Пишем кронтаб. На какое время он будет вешаться — особого значения нет. Я вызываю его раз в 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.


Send by E-mailSend by E-mail   Print versionPrint version
Comments(0)

No comments yet… Be the first to leave comment on this topic!

or
You may sign in using:
Enter with Facebook Enter with Google Enter with VK