Кеширование или как много хорошего в этом слове

Думаю не для многих разработчиков есть секретом что в ЛС встроен механизм кеширования информации, полученной от БД. Но мои частые наблюдения сообщают о другом — я не могу вспомнить сторонние плагины, которые использовали бы кеширование в своей работе. Да что лукавить — я сам его обходил стороной часто. Поэтому этот топик призван пролить луч света на использование кеширования в ЛС в своих плагинах, т.к. это довольно просто.
Итак, главное в вашем плагине определить точки где вы получаете данные и где их записываете/модифицируете. Я понимаю что это несложно — в маппере, но все же.
Кеширование должно работать по логике: пока данные не менялись — тащим их с закромов, а не выколачиваем из БД.
Потому придем к обобщенным примерам (они упрощенные):
1. Там где у вас идет изменение данных в БД (insert, update, delete) — чистим то, что сохранили в кеше т.к.
2. Там где идет выборка данных (select) — проверяем:
- Есть ли данные которые хотим получить в кеше? Если есть — то возвращаем из кеша
- Есть ли данных нет, то нужно их получить путем запроса к БД и то что получили тут же упрятать в
каморкув кеш
Вроде как логично? Да. Теперь более подробно и с деталями. У модуля кеша ЛС есть интересные функции:
- Получение данных из кеша по имени, геттер
- Занесение данных в кеш по имени, сеттер
- Очистка кеша по имени, тегам
Имя — некое символическое представление того что вы ищете в БД. Например, вы хотели бы получить список книг от автора с ИД=2, вы бы выполнили запрос в БД где указали условие:
SELECT * from `books` WHERE `author_id` = 2
Вот и в кеше можно было сохранить результат выборки под именем, например, «book_author_2», а потом пока данные не меняются — таскать данные не из БД, а сохраненного значения.
Вот теперь собственно и сам код:
1. Когда делаем выборку (select) — ищем информацию в кеше по имени, например, «book_author_2», есть — возвращаем её, нету — берем из БД, сохраняем в кеш. И потом её возвращаем:
if (false === ($data = $this -> Cache_Get ("book_author_{$iAuthorId}"))) {
$data = $this -> oMapper -> GetBooksByAuthorId ($iAuthorId);
$this -> Cache_Set ($data, "book_author_{$iAuthorId}", array ("book_change_{$iAuthorId}"), 60*60*24*3);
}
2. Когда делаем изменения в БД (insert, update), чистим кеш по тегам:
$this -> Cache_Clean (Zend_Cache::CLEANING_MODE_MATCHING_TAG, array ('book_change', "book_change_{$oBooks -> getId ()}"));
3. Когда удаляем данные из таблицы — удаляем кешированный результат, который может содержать значение которое мы удаляем:
$this -> Cache_Clean (Zend_Cache::CLEANING_MODE_MATCHING_TAG, array ('book_change', "book_change_{$oBooks -> getId ()}"));
Я не сказал ещё о важном параметре — тегах кеша. Именно их мы видим в сеттере 3 параметром и при удалении данных. Т.е. при занесении информации нужно указать к чему эта информация относится, например, к получению лучших авторов книг на сайте. И если удалять автора, то удаление затронет выборку лучших авторов, поэтому при удалении в тегах можно указать и тег получения лучших авторов — это кеш будет сброшен и заново установлен при следующей выборке.
В сеттере видим последний параметр — это время действия кеша по-умолчанию. Т.е. если данные не изменятся 3 суток, то кеш потом все равно будет сброшен автоматически.
Код кеширования обычно ложится в модули плагинов.
Надеюсь эта статья поможет авторам плагинов для ЛС сделать их более быстродействующими.
Ну и напоследок хотелось бы сказать — лучшая документация по ЛС — это его исходники. Изучайте.
З.Ы. Использование кеша необходимо только там где в этом есть целенаправленная необходимость — мало меняющиеся данные, которые очень часто получают из БД. Если данные подвергаются постоянной смене, но использование кеша сомнительно.
Старый кеш (тот у которого вышло время) удаляется в ЛС постепенно. Кому интересно — engine/modules/cache/Cache.class.php, с 95 строки :)
UPD: Забыл добавить — удаление кеша по имени:
$this -> Cache_Delete ("book_change_{$oBooks -> getId ()}");
спасибо legioner
17 комментариев
sitemap, l10n, etc
Я допустим делаю запрос в DB и записываю данные в cache
и что значит в этом случае array(«advert_update»,«advert_new») и если не правильно то как должно быть..?
Следующий отрезок кода по идее должен чистить Cache
но если я записывал переменные как advert_{$oAdvert->getAdsId()} то и чистить должен их как 'advert',«advert_{$oAdvert->getAdsId()}» а не так как показано на примере.
вот этого уже хватит для очистки кеша. т.е. удаляется весь кеш, который содержит указанны тег
сдесь важно понять что удаление не по имени, а по тегам.
я не совсем понял.
это будет имя для кеша:
это будет тег для кеша (допустим, один):
очистить весь кеш, который был занесен с указанием тега «advert»:
То есть мне лучше всего сделать так…
получается $tag = «advert_{$oAdvert->getAdsId()}»; == «advert_{$oAdvert->getAdsId()}» в array и второй раз мне это не нужно писать и просто сделать array(«advert»)..?
А чистить я получается смогу или всё с тегом «advert» или только то значение которое мне нужно «advert_{$oAdvert->getAdsId()}»
Или опять я чего то не учёл..?
А как тогда сделать что бы можно было при обновлении не очищать все переменные с тегом advert а очистить или удалить только кешь где тег advert_{$oAdvert->getAdsId()}
Когда всё сделал по аналогии с топиками LS и применил функции GetModulsByArrayId и GetModulsAdditionalData, плюс кешироваться стало всё стабильно, работоспособность выросла в разы…
MySql
query: 255
time: 0,566
Cache
query: 0
— set: 0
— get: 0
time: 0
если бы были проблемы с правами — был бы ворох ошибок