Хаки установленных модулей Drupal
Изменение модуля 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, получает информацию о всех нодах, которые будут выведены на странице, и помещает её в кэш. Все следующие запросы будут обращаться к кэшу минуя базу данных, что дает прирост производительности.
Источники: