24 февраля 2013 г.

В предыдущем сообщении была разобрана одна из причин дополнительной нагрузки на базу данных из-за неправильной обработки кэша. Проверив теорию на практике, было также найдено избыточное обращение к модели категорий, что также является, в некоторой степени, причиной снижения быстродействия.

В перечисленных ниже файлах вычисляются количество продуктов для каждой категории. Количество будет показано только в том случае, если включена соответствующая опция config_product_count в панели администрирования магазином.

./catalog/controller/module/category.php
./catalog/controller/product/category.php
./catalog/controller/common/header.php

Однако несмотря на саму возможность отключения показа количества продуктов в меню категорий, нагрузка остаётся и проблема в условии их показа:

$product_total = $this->model_catalog_product->getTotalProducts($data);
...
'name'  => $result['name'] . ($this->config->get('config_product_count') ? ' (' . $product_total . ')' : ''),
...

Очевидно обращение к модели не имеет смысла, если показ отключён. Более верным решением будут следующие строчки кода:

$product_total = '';
...

if ($this->config->get('config_product_count')) {
$product_total = $this->model_catalog_product->getTotalProducts($data);
$product_total = ' (' . $product_total . ')';
}

Стоит отметить, что игнорирование подобных недочётов в конечном счёте приводит к значительным потерям в производительности сервера. 

23 февраля 2013 г.

Использование кэша в OpenCart позволяет сократить количество обращений к базе данных и увеличить быстродействие магазина, однако есть некоторые нюансы в работе самого кэша.

Управление кэшем происходит в файле ./system/library/cache.php, если обратить внимание на функцию get, то видно, что результат возвращается функцией php unserialize когда файл кэша есть и null, когда его нет. Это значит, что если в кэше сохранён результат пустой выборки в одной из моделей, то при очередном запросе кэша будет возвращён ноль.

Практически во всех моделях условие проверки кэша следующее:

$product_data = $this->cache->get( ...

if (!$product_data) { ...

что в корне неверно, так как содержание кэша, например, строка s:1:"0";, может сообщить модулю об его "отсутствии" и будет выполнено повторное обращение к базе.

Если создать новые категории, то это будет хорошо заметно. Товаров нет, каждый раз запрос из базы возвращает пустой результат и сохраняет его в кэше. В этом конкретном примере необходимо открыть файл ./catalog/model/catalog/product.php найти функцию getTotalProducts и в её теле заменить условие

if (!$product_data) { ...

на

if ($product_data === null) { ...

Теперь существование кэша будет правильно воспринято отдельно взятой функцией того или иного модуля. Исправления актуальны для всех версий OpenCart, включая последнюю v1.5.5.1.

Update

Работая с библиотекой кэша ./system/library/cache.php обратил внимание, что принцип выдачи кэшированной информации организован неверно. Модулю, запросившему кэш, может быть выдана устаревшая информация, если обратите внимание на код, то данные с файла считываются раньше проверки на время.

Дабы не создавать отдельную статью, приведу решение здесь. Функцию get() необходимо заменить на код ниже.

public function get($key) {
$data = null;
$files = glob(DIR_CACHE . 'cache.' . preg_replace('/[^A-Z0-9\._-]/i', '', $key) . '.*');
if ($files) {
for ($n=0, $lenght = count($files); $n < $lenght; $n++) {
$file = $files[$n];
$time = substr(strrchr($file, '.'), 1);
      if ($time < time()) {
if (file_exists($file)) { unlink($file);
      } elseif (!$n) { $cache = file_get_contents($file); $data = unserialize($cache);
} } return $data; }

Кстати, обновлённная функция работает немного быстрее, т.к. используется цикл for next (призываю использовать в PHP вместо foreach везде) и unserialize выполняется не по умолчанию, а только если кэш не устарел.

Если у Вас недостаточно опыта по внесению изменений в программный код OpenCart, то мы готовы предложить со своей стороны помощь.
  • RSS
  • Twitter
  • Youtube