Кэшируй, кэшируй, кэшируй запрос назло буржуазной Европе!
Предыстория этого вопроса такова: одно время магаз на ShopScript работал у меня на довольно хилом VDS и посещения поисковых ботов практически клали сервер на обе лопатки. Типичная, так сказать, DDOS атака :-) Поэтому я озаботился производительностью самого скрипта. Предпринял следующие логичные, как мне кажется, шаги:
- Добавил недостающие индексы в разные таблицы с товаром, параметрами товара, категории, валюты и т.д.
- Убрал подсчет запросов категорий и товаров. Во-первых это оказалась бесполезная фича, во-вторых это было просто.
- Закэшировал несколько запросов.
Эти три пункта помогли решить проблему. Не знаю, какой оказал бОльшее влияние, но первого точно было недостаточно.
Объяснять как установить PEAR, добавить в include_path путь до него не буду.
Первый вариант кэширования я сделал с помощью класса Cache_Lite из PEAR. В общем-то можно было бы обойтись и просто сохранением в файл, но мне не улыбалось писать код для сравнения даты создания файла, вычисления устаревания кэша и т.д. – все это уже сделано, зачем мне писать то же самое?
Что бы нам такого закэшировать? Посмотрим код ShopScript’a. Ух-ты! Есть вот такой перл в самом index.php:
//load all categories to array $cats to avoid multiple DB queries //(frequently used in future - but not always!) $cats = array(); $i=0; $q = db_query("SELECT categoryID, name, parent, products_count, description, picture FROM ". CATEGORIES_TABLE." where categoryID<>0 ORDER BY sort_order, name") or die (db_error()); while ($row = db_fetch_row($q)) { $cats[$i++] = $row; }
Загружаются подряд все категории товаров! Когда это 5-10 категорий – не очень страшно. Если общее количество категорий приближается к сотне, да еще есть описания, то общий объем данных получается очень приличным. Да еще этот код срабатывает при каждом запуске скрипта, нужен-не нужен – пофиг.
Категории меняются редко, поэтому вполне достаточно выполнять такой запрос, скажем, раз в сутки. Вот этим и займемся.
Создадим директорию cache и разрешим скрипту туда запись. Если директория в корне сайта, лучше в нее добавить файлик .htaccess со строчкой ‘Deny from all’.
В начало index.php добавим подключение класса Cache_Lite и создание экземпляра класса. У меня получилось вот так:
$cache_options = array( 'cacheDir'=>$_SERVER['DOCUMENT_ROOT'] . '/cache/', 'lifeTime'=>86400); $cache_categories_id = 'category'; require_once('Cache/Lite.php'); $CacheLite = new Cache_Lite($cache_options);
В переменной $cache_categories_id – метка, по которой будет извлекаться данные из кэша. В общем, доку по Cache_Lite надо хотя-бы просто просмотреть.
А код, где делается запрос к БД на выборку изменим на такой:
//load all categories to array $cats to avoid multiple DB queries //(frequently used in future - but not always!) if ($cats_str = $CacheLite->get($cache_categories_id)) { $cats=unserialize($cats_str); } else { $cats = array(); $i=0; $q = db_query("SELECT categoryID, name, parent, products_count, description, picture FROM ". CATEGORIES_TABLE." where categoryID<>0 ORDER BY sort_order, name") or die (db_error()); while ($row = db_fetch_row($q)) { $cats[$i++] = $row; } $CacheLite->save(serialize($cats), $cache_categories_id); }
Вот и все. Еще в том же index.php есть запрос на выборку всех валют – тоже хороший кандидат на кэширование.
Еще можно внимательно рассмотреть запросы при выводе информации о товаре (includes/produc_detailed.php) и подумать о том, что информацию о товаре тоже можно кэшировать. Но в случае изменения неплохо бы и сбрасывать кэш.
Схема с PEAR::Cache_Lite прожила довольно долго. VDS я сменил на другой, у которого памяти побольше было и это позволило установить кэшер байткода XCache. А некоторое время назад я обнаружил, что ZendFramework научился работать с этим самым XCache. И я переделал работу с Cache_Lite на Zend_Cache с бэкендом XCache. Теперь переменные хранятся вообще в памяти.
-
Антон
-
Антон
-
Сергей
-
Сергей
-
Den
-
Сергей
-
Den
-
Serg
-
Сергей
-
Serg



