xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Уменьшаем количество запросов к MySQL в полтора раза

Опубликовано в

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

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

Если у вас хороший хостинг с включённым query_cache у MySQL, на это можно не обращать внимания. Однако меня такое положение дел не устраивает :) Будем резать!

Открываем файл includes/path.inc, идём в строчку 63 и находим там такой кусок:

    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, информация обо всех псевдонимах попадает в кэш, и в будущем берётся от туда, минуя БД.

Вот логи модуля Devel до и после патча:

Executed 207 queries in 211.37 milliseconds.
Executed 139 queries in 131.15 milliseconds.

−68 запросов!

Результаты теста утилитой ab, кэширование отключено, до и после патча:

Requests per second: 3.05-3.62 (в основном 3.50)
Requests per second: 3.71-4.01 (в основном 3.90)

Минусом этого патча является то, что из базы вытаскиваются все псевдонимы, независимо от того — используются они на странице или нет.

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

Написанное актуально для Drupal 6.14-6.17
Похожие записи

Комментарии RSS

Супер спосибо

Если memcache подключен, то можно использовать патч от ванДюка.

Кеш синонимов сбрасывается каждый раз когда я добавляю в базу новый синоним?

Кеш синонимов сбрасывается каждый раз когда загружается очередная страница

интересно, а в 7-ке как обстоят дела с запросами? не смотерли случайно?

спасибо.
в целом это грустно... но да ладно, что не потерпеть ради любимого друпала =)

Автор статьи неприменно прав. Сам я тоже дошел до этого исследуя запросы к базе на довольно тяжелом ресурсе.

Но есть одно но. Если Ваш ресурс больших объемов и таблице алиасов храниться большое кол-во записей (в моем случае больше 10k - и хватило), то картина следующая:
- без хака: около 100 запросов по ~2мс на одной странице.
- с хаком: 1 запрос, но ~ 400мс.

В моем случае что тот первый вариант что второй одинаково ужасные. Поэтому да здравствует memcache.

Эффект обратно пропорциональный. Потребление памяти возрастает на моей конфигурации в 10 раз, как и время обработки страницы примерно в 8.

где-то накосячил

По части ядра(6.22) я очень мало чего трогал в отношении путей и алиасов. Код просто перенёс и всё. Может быть какой-то модуль хардкорит, не важно в принципе :)

Вот за это:

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

Спасибо

Что делал с Уведомлять меня о новых комментариях? У тебя ведь 6 стоит?

ничего не делал. да 6

Ясно.

Спасибо большое!
нагрузка на базу сократилась почти в 4 раза! ускорения нет, но зато нет и оверлимитов :)
А вы не знаете случайно не появился ли способ избавления от минуса, например, путем сохранения кэша в отдельной таблице или еще как то? ...для 6, не могу с нее уйти :(

ой, не то написала, не в 4 раза, а на 25% почти :)

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании