После анализа лога дебаггера на сборке в которой также установлен Advanced SEO URL выяснилась интересная вещь из 450 запросов к б.д. основную часть (~300 запросов) берет 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');