Хаки установленных модулей Drupal

Изменение исходного кода Drupal на предмет уменьшения числа запросов к MySQL.

Изменение модуля Path

Один из самых затратных (в плане работы с MySQL) модулей в Drupal это Path. Для каждой ссылки, будь то ссылка на ноду, термин или форму ответа в комментариях, модуль создаёт запрос к таблице url_alias с целью выяснить, не добавили ли мы для этой ссылки alias, и если добавляли, то использовать его вместо дефолтного url.

Например у вас включён модуль Path и Pathauto. Pathauto создаёт псевдонимы для записей типа "Блог" вида "/blog/nid". Тогда для того чтобы вывести 10 последних записей в блоге, модуль Path сделает 10 запросов к MySQL. Если при этом у каждой записи есть теги, то Path сделает ещё по запросу на каждый тег. В итоге, на этом блоге, Path создаёт около 70 запросов.

Решение предлагается для версии  Drupal 6.14. Для других версий код может отличаться.

В файле includes/path.inc, в строчке 64 код:

    if ($action == 'alias') {
      if (isset($map[$path_language][$path])) {
        return $map[$path_language][$path];
      }
      // Get the most fitting result falling back with alias without language
      $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language));
      $map[$path_language][$path] = $alias;
      return $alias;
    }

Заменяем на:

    // start hack ----
    if (count($map) == 0) {
      $allAliasResult = db_query("SELECT src, dst FROM {url_alias}");
 
      while ($row = db_fetch_array($allAliasResult)){
        $map[$path_language][$row['src']] = $row['dst'];
      }
    }
    // end hack ------
 
    if ($action == 'alias') {
      if (isset($map[$path_language][$path])) {
        return $map[$path_language][$path];
      }
      // start hack ----
      else { return false; }
      // end hack ------
 
      // Get the most fitting result falling back with alias without language
      $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language));
      $map[$path_language][$path] = $alias;
      return $alias;
    }

При первом вызове функции drupal_lookup_path, информация обо всех псевдонимах попадает в кэш, и в будущем берётся от туда, минуя БД. Минусом этого патча является то, что из базы вытаскиваются все псевдонимы, независимо от того — используются они на странице или нет.

Примечание: данный патч предназначен только для одноязычных сайтов.

Изменение модуля Comment

На каждый запрос информации о ноде, например вывод тизера на главной, модуль Comment выполняет запрос к БД, в котором достаёт число комментариев к этой ноде и информацию о последнем комментарии. Если эта информация нам не нужна, например в блоге она нигде не выводится, можно избавится от десятка запросов, с помощью правки ядра.

Решение предлагается для версии  Drupal 6.14. Для других версий код может отличаться.

Для этого открываем файл modules/comment/comment.module и в строке 596 находим  кусок кода:

    case 'load':
      return db_fetch_array(db_query("SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = %d", $node->nid));
      break;

Комментируем его:

    //case 'load':
      //return db_fetch_array(db_query("SELECT last_comment_timestamp, last_comment_name, comment_count FROM {node_comment_statistics} WHERE nid = %d", $node->nid));
      //break;

 

Дальше в строке 1120 вместо

function comment_num_all($nid) {
  static $cache;
 
  if (!isset($cache[$nid])) {
    $cache[$nid] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
  }
  return $cache[$nid];
}

вставляем:

function comment_num_all($nid) {
  static $cache;
 
  if (!isset($cache[$nid])) {
    //$cache[$nid] = db_result(db_query('SELECT comment_count FROM {node_comment_statistics} WHERE nid = %d', $nid));
    $cache[$nid] = 0;
  }
  return $cache[$nid];
}

 

Изменение модуля Node

При выводе тизеров Drupal делает под одному запросу на каждую ноду. Например при выводе 10 последних записей, будет сделано 10 массивных запросов к таблице node. В этих запросах пересекаются две таблицы - user и node_revisions, чего можно избежать.

Решение предлагается для версии  Drupal 6.14. Для других версий код может отличаться.

В файле modules/node/node.module в строчке 748 код:

  else {
    $node = db_fetch_object(db_query('SELECT '. $fields .' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE ' . $cond, $arguments));
  }

Меняем  на:

  else {
    // start hack
    if ($_GET['q'] == 'node') {
 
      static $cachedNodes = array();
 
      if (count($cachedNodes) == 0) {
        $page = isset($_GET['page']) ? (int)$_GET['page'] : 0;
        $perPage = variable_get('default_nodes_main', 10);
 
        $cachedNodesResult = db_query('SELECT ' . $fields . ' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid ORDER BY n.nid DESC LIMIT %d, %d', $page * $perPage, $perPage);
 
        while ($row = db_fetch_object($cachedNodesResult)) {
          $cachedNodes[$row->nid] = $row;
        }
      }
 
      if (isset($cachedNodes[$param])) {
        $node = $cachedNodes[$param];
      }
    }
 
    if (!isset($node)) {
      $node = db_fetch_object(db_query('SELECT '. $fields .' FROM {node} n INNER JOIN {users} u ON u.uid = n.uid INNER JOIN {node_revisions} r ON r.vid = n.vid WHERE ' . $cond, $arguments));
    }
    // end hack
  }

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

Источники:

http://xandeadx.ru/blog/drupal/

Вам также может помочь