Оптимизация Opencart: уменьшаем количество обращений к базе в режиме SEO URL

SEO URL важная функциональная часть в программном обеспечении OpenCart, объяснять её востребованность нет смысла, достаточно вспомнить технологии SEO. Режим SEO-ссылок включается в панели администрирования в настройках магазина (закладка Сервер).

Вроде всё понятно, но есть одна проблема - это существенная нагрузка на базу данных! Это, пожалуй, самая затратная часть в плане расхода вычислительных ресурсов сервера. С ростом количества товаров и посетителей замедление в работе магазина становится настоящей проблемой! Можно, конечно, выбрать оборудование получше, но если вы собираетесь серьёзно заниматься онлайн-коммерцией, то в какой-то момент времени посмотрите на счета за услуги хостинга и удивитесь сумме ежемесячных платежей. Именно решением этой проблемы мы и занимаемся.

Чтобы понять, как работает режим SEO URL, необходимо разобрать алгоритм формирования и распознания таких ссылок. Весь процесс происходит в файле ./catalog/controller/common/seo_url.php.

По умолчанию система формирует ссылки в стандартном виде и только в режиме SEO URL они преобразуются функцией rewrite. Выглядит это следующим образом:
Контроллер формирует контент с сылками, которые форматируются в библиотеке ./system/library/url.php. Если режим SEO URL активен (см. config_seo_url), то после каждого форматирования ссылки она разбивается на составные части, которые сверяются с содержимым таблицы базы данных url_alias в поиске значения keyword. Это значение закрепляется пользователем при редактировании категории, продукта, статьи или производителя.
При преходе пользователем по SEO-ссылке со страниц магазина или с результатов выдачи поисковой системы происходит обратное преобразование ссылки в стандартный формат. Она также разбивается на части (разделителем служит прямой слэш), которые сверяются с таблицой url_alias в поиске идентификаторов категории, продукта, статьи или производителя.
Независимо от того, присвоили ли вы ключевое слово (keyword) категории, продукту, статье или производителю, обращения к базе в этом режиме будут постоянны. Чем глубже ссылка и чем больше их количество, тем медленнее будет работать ваш магазин.

Последний момент усугубляется наличием циклов foreach, в котором для каждой части ссылки происходит обращение к базе данных. Логично было бы построить один запрос для всех частей ссылки:

В файле seo_url.php часть содержимого функции index() после строки $parts =
explode('/', rtrim($this->request->get['_route_'], '/')); и до
if (isset($this->request->get['product_id'])) {
      $this->request->get['route'] = 'product/product';
...

необходимо заменить на следующий код:
if (count($parts)) {
     $parts =  array_map(array($this->db, 'escape'), $parts);
     $db_query = $this->db->query("
     SELECT SUBSTRING_INDEX(query,'=',1) AS name,
     CONVERT(SUBSTRING_INDEX(query,'=',-1),UNSIGNED INTEGER) AS value
     FROM " . DB_PREFIX . "url_alias WHERE keyword IN('" . implode("','", $parts) . "') ORDER BY
     FIND_IN_SET(keyword, '" . implode(",", $parts) . "')
     ");
 if ($db_query->num_rows) {
  foreach($db_query->rows as $row) {
   if($row['name'] == 'category_id') {
    if (!isset($this->request->get['path'])) {
      $this->request->get['path'] = $row['value'];
    } else { 
      $this->request->get['path'] .= '_' . $row['value'];
    }
   } else $this->request->get[$row['name']] = $row['value'];
  }
 } else $this->request->get['route'] = 'error/not_found';  
}

В том же файле, но уже для функции rewrite() после строки
parse_str($url_data['query'], $data); и до if ($url) {
            unset($data['route']);
            ...

содержимое необходимо заменить на код ниже:
$queries = array();
foreach ($data as $key => $value) {
    if (isset($data['route'])) {
     if (($data['route'] == 'product/product' && $key == 'product_id') || 
        (($data['route'] == 'product/manufacturer/info' || 
          $data['route'] == 'product/product') && $key == 'manufacturer_id') || 
        ($data['route'] == 'information/information' && $key == 'information_id')) {     
          $queries[] = $key . '=' . (int)$value; 
          } elseif ($key == 'path') {
          $categories = explode('_', $value);
           foreach ($categories as $category) {
               $queries[] = "category_id=" . (int)$category;
          }
      }
    }
 }

if (count($queries)) {    
    $cache = md5(http_build_query($queries));
    $rows = $this->cache->get('url.alias.' . (int)$this->config->get('config_store_id') . $cache);
    if (!$rows) {
     $db_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "url_alias 
                           WHERE `query` IN('" . implode("', '", $queries) . "')");
     $rows = $db_query->rows;
     $this->cache->set('url.alias.' . (int)$this->config->get('config_store_id') . $cache, $rows );
    }
    foreach ($queries as $query) {   
     foreach ($rows as $row) {
      if($row['query'] == $query) {
       $url .= '/' . $row['keyword'];
       $query = explode('=', $query);
       $key = array_shift($query);
       $key = ($key=='category_id') ? 'path' : $key;       
       unset($data[$key]);
       break;
      }
     }   
  }
}

Обратите внимание, что в эту функцию добавлено также кэширование запросов к базе данных, это уже комплексное решение, которое сводит влияние режима SEO URL на производительность сервера к существенному минимуму (вместо 30-100 запросов всего 5-10).

При использовании кеширования не забудьте его сбрасывать после изменения/создания категории, продукта, статьи или производителя. Для этого в модели этих объектов наравне с удалением собственного кэша добавьте строчку кода $this->cache->delete('url.alias');
* * *

Дополнительное решение для тех, кто понимает насколько важным является наименование и переименование ссылок.
Всем известна пословица, как корабль назовешь, так он и поплывет. Это определение можно применить и к ссылкам. Речь идет не только о формате ссылок, но и об их звучании и зрительном восприятии. В первом случае это качественное ранжирование в поисковых системах, а во втором - реклама ресурса при обмене ссылками между пользователями, например, в социальных сетях.

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

Если просто переименовать ссылку объекта в OpenCart, то по старому адресу страница окажется недоступной (404 Not Found), а это чревато потерей потенциальных клиентов и позиций в поисковой выдаче. Выходом из данной ситуации может стать редирект с кодом 301 на новый адрес страницы.

В данном решении используется история переименований объектов OpenCart в виде дополнительной таблицы url_alias_archive, представления url_alias_view, двух триггеров и одного события (event). В файл ./catalog/controller/common/seo_url.php вносятся небольшие коррективы. Заказать решение можно у автора статьи.
Теги:
seo url, поисковая оптимизация
Добавлено: 13 Января 2015 09:52:18 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...