Разработчику. Сборник рецептов PHP
Задавайте вопросы

Кэширование запросов и результатов

Вернуться назад

Задача

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

Решение

Используйте пакет PEAR Cache_DB. Он предоставляет в качестве оболочки уровня абстракции базы данных DB объект, который имеет схожие методы и автоматически кэширует результаты запросов SELECT:

require 'Cache/DB.php';

$cache = new Cache_DB;
$cache->connect('mysql://test:@localhost/test');

$sth = $cache->query("SELECT sign FROM zodiac WHERE element LIKE 'fire'");

while($row = $sth->fetchRow()) {
     print $row['sign']."\n";
}

Обсуждение

Пакет Cache_DB используется почти так же, как и DB, но есть некоторые существенные отличия. Во-первых, требуется файл Cache/DB.php вместо DB.php. В этом случае файл Cache/DB.php загружает соответствующие классы DB. Вместо того чтобы посредством метода DB::connect() создавать спецификатор базы данных, с помощью оператора new создается объект Cache_DB, а затем вызывается метод connect() этого объекта. Синтаксис метода $cache->connect() тот же самый, однако ему достаточно передать DSN, идентифицирующий базу данных. Метод query() пакета Cache_DB работает точно так же, как и в DB, однако в Cache_DB нет методов prepare() и execute(). Метод query() возвращает спецификатор оператора, поддерживающего методы etchRow() и fetchInto(), но режим выборки по умолчанию определяется константой DB_FETCH_ASSOC, а не DB_FETCH_ORDERED.

Когда какой-либо оператор SELECT первый раз передается методу $cache->query(), то Cache_DB выполняет оператор и возвращает результаты точно так же, как и DB, но помимо этого он записывает результаты в файл, имя которого представляет собой хеш запроса. Если тот же самый оператор SELECT снова передается методу $cache->query(), то вместо того что-бы запрашивать базу данных, Cache_DB извлекает результаты из файла.

По умолчанию Cache_DB создает свои кэш-файлы в подкаталоге текущего каталога с именем db_query. Его можно изменить, передав имя каталога в составе массива параметров как второй аргумент конструктору Cache_DB. Следующий оператор определяет кэш-каталог как /tmp/db_query:

$cache = new Cache_DB('file',array('cache_dir' => '/tmp/'));

Первый аргумент, file, указывает Cache_DB, какой контейнер использовать для хранения кэшированных данных. По умолчанию это значение file, но при этом необходимо указать еще и параметры контейнера во втором аргументе. Подходящим является cache_dir, указывающий Cache_DB, где создавать подкаталог db_query. Символ косой черты в конце обязателен.

По умолчанию информация в кэше хранится в течение часа. Этим временем можно управлять, передавая другое значение (в секундах) при создании нового объекта Cache_DB. Ниже показано, как сохранить инормацию в кэше в течение одного дня, или 86 400 секунд:

$cache = new Cache_DB('file',array('cache_dir' => '.',
                    'filename_prefix' => 'query_'),86400);

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

Содержимое кэша остается прежним, даже если база данных изменяется в результате запросов INSERT, UPDATE, или DELETE. Если в кэше хранится результат оператора SELECT, относящийся к данным, которых уже не существует в базе данных, то необходимо полностью очистить кэш непосредственно с помощью метода $cache->flush():

$cache->flush('db_cache');

Очень важно включить аргумент db_cache в вызов lush(). Кэш-система в PEAR поддерживает разделение кэшированных данных на различные группы, а объект Cache_DB помещает всю информацию, за которой он следит, в группу db_cache. Пропуск аргумента группы приведет к удалению файлов из базового каталога кэша (из которого, возможно, запускается ваш сценарий).

Файловый контейнер хранит каждый результат в файле с именем, основанным на MD5-хеше запроса, сгенерировавшего определенный результат. Поскольку MD5 чувствителен к регистру, то и файловый контейнер также чувствителен к регистру. Это означает, что если результаты запроса SELECT * FROM zodiac находятся в кэше, а запускается запрос SELECT * from zodiac, то его результаты не будут найдены в кэше, и он будет запущен как новый запрос. Последовательное применение заглавных букв, пробелов и порядка полей при создании запроса приводит к более эффективному использованию кэша.

Этот рецепт посвящен, в основном, файловому контейнеру, но кэшсистема в PEAR поддерживает множество других контейнеров, хранящих кэшированные данные, например, разделяемую память, PHPLib-сеансы, базы данных на основе библиотеки dbx и сеансы msession. Для того чтобы использовать другой контейнер, надо при создании нового объекта Cache_DB передать соответствующее имя контейнера в качестве первого аргумента:

$cache = new Cache_DB('shm');

Вернуться назад

Рейтинг@Mail.ru

Яндекс.Метрика

Индекс цитирования


Рейтинг Сайтов ДОСКИ.РУ