Кеширование с помощью статических переменных и в моделях CakePHP
Как вы оцениваете свой уровень как программиста? Несмотря на то, что меня Влад дважды похвалил :), я свой уровень оцениваю на 3 с плюсом (по 5-бальной шкале). Каждый день узнаю такие интересные финты, что хочется посыпать голову пеплом, за то, что сам до этого не додумался.
Сегодня узнал способ легко кешировать результаты функции, которые не меняются при условии одинаковых входящих параметров.
Если результаты очень объёмные и слишком расточительно кешировать всё, можно проверять время и кешировать только то, расчёт чего занимает больше 1 секунды.
-
function test($input) {
-
-
// Сама функция, которая как на зло иногда быстрая, а иногда очень долгая
-
// Обрабатываем $input и получаем $result
-
-
return $result;
-
}
Я иногда делаю кеширование в моделях CakePHP. Причины кеширования - таблица содержит больше 200 тысяч записей (схожие принципы используются в других таблицах с десятками миллионов записей), запросов очень много, но в течение дня запросы часто идут к одним и тем же записям. Дописывается в таблицу что-то очень редко. Полностью модель довольно сложная и имеет множество взаимосвязей, я показываю только маленькую часть, чтобы можно было понять принцип.
-
<?php
-
class Word extends AppModel {
-
-
var $name = 'Word';
-
'id' => VALID_NUMBER,
-
'name' => VALID_NOT_EMPTY,
-
);
-
-
-
function __construct($id=false, $table=null, $ds=null) {
-
$this->cache = Cache::read('word_list');
-
if ($this->cache===false) {
-
}
-
-
return parent::__construct($id, $table, $ds);
-
}
-
-
function __destruct() {
-
Cache::write('word_list', $this->cache);
-
-
//return parent::__destruct(); // AppModel hasn't __destruct method
-
}
-
-
function getNames($ids) {
-
foreach ($ids as $id) {
-
$newIds[] = $id;
-
} else {
-
$result[$id] = $this->cache[$id];
-
}
-
}
-
-
$this->cache[$id] = $name;
-
$result[$id] = $name;
-
}
-
-
return $result;
-
}
-
}
-
?>
, ... . .
static , .
@larin: . ?
memcached
Zend framework Cache Function.
CakePHP Zend.
Zend . .
PS:
@Евгений: ну, не знаю. почитал
http://framework.zend.com/manual/en/zend.cache.html
и не нашёл ничего, чего бы не смог сделать с помощью кейковского Cache. Не то, чтобы Zend_Cache плохой - он действительно более продвинутый, но он в стиле Zend, а не Cake.
Например, в Cake разделено просто кеширование и кеширование View/Element, что позволяет использовать кеш в FrontEnd, даже не думая о настройках. В Zend придётся думать, настраивать. Я предпочитаю о кеше не думать, пусть фреймворки за меня думают. Хотя, наверное, я так говорю, потому что для всех моих проектов с головой хватало одного выделенного сервера; для более масштабных проектов есть смысл в более вдумчивой оптимизации.
IMHO не полное решение:
1. В чем будет разница между http://dev.mysql.com/doc/refman/5.0/en/query-cache.html и помещением Cake cache в таблицу?
2. Что мешает использовать var $cacheQueries = true; в AppModel?
3. DRY нарушено - если всетаки надо кэшить (к примеру DB сильно далеко, или не DB вовсе а обертка над сервисом), почему не сделать "приватными" методы возможно подлежащие кэшированию и использовать __call в AppModel для реализации кэширования?
@KPOTOB:
1. Cake cache хранится в файлах (по умолчанию). Если файлов не миллион, а записей в MySql - миллион, то будет быстрее обратиться к файлу.
2. Кеширование должно быть не только в пределах одной сессии.
Cake API :: AppModel :: $cacheQueries
00194 * Whether or not to cache queries for this model. This enables in-memory
00195 * caching only, the results are not stored beyond this execution.
...
00200 var $cacheQueries = false;
3. Согласен. Так как этот способ кеширования используется в нескольких моделях, то моя реализация ужасна с точки зрения DRY. Только, наверное, в стиле Cake лучше реализовать это с помощью Behavior, переопределяя метод beforeFind (&$model, $query). Интересная мысль, спасибо. Меня тоже это сильно смущало.
@Владимир Лучанинов: А как быть с инвалидацией кэша?
@KPOTOB:
В Cake автоматически перестраивается кеш View, Elements при изменении данных.
Кеш, который делается вручную Cache::write, имеет ограниченный срок жизни (по умолчанию - час).
Это не оно?
@Владимир Лучанинов: в том часе и дело - если источник - какаянибуль жирная таблица разузлования для производства то наверное не плохо - а если чтото динамическое - то хреново
Добавлю к предыдущиму
Кэш запросов в базе инвалидиться атоматически при записи;
var $cacheQueries = true в моем случае при вызове findAll с рекурсией 4 (не нужные ассоциации убраны через unbindModel) убали колво запросов с ~2200 до ~250;
Кэш view будет работать быстрее - в общем не сильно позитив, а горя хлебнуть можно прилично при двух кэшах в app
@KPOTOB: Да, в этом случае согласен. Динамическое - хреново, если рекурсия 4.
Но ведь таких случаев мало. Поэтому я люблю, чтобы за меня думал динамический фреймворк. А потом с профайлером находятся часто вызываемые узкие места и дорабатываются вручную. Если всего несколько раз в день делается такая сложная операция и она занимает 7 секунд вместо 0.7, то часто можно не обращать на это внимание.