Недавно я прочитал статью в блоге 37Signals, и мне интересно, как они получают ключ кеша.
Хорошо, когда у вас есть ключ кеша, который включает временную метку объекта (это означает, что при обновлении объекта кеш будет признан недействительным); но как тогда использовать ключ кеша в шаблоне, не вызывая попадания в БД для самого объекта, который вы пытаетесь извлечь из кеша.
В частности, как это влияет на отношения Один-ко-многим, например, когда вы отображаете Комментарии к Посту.
Пример в Джанго:
{% for comment in post.comments.all %}
{% cache comment.pk comment.modified %}
<p>{{ post.body }}</p>
{% endcache %}
{% endfor %}
Кеширование в Rails отличается от просто запросов к memcached, например (я знаю, что они конвертируют ваш ключ кеша во что-то другое). Они тоже кешируют ключ кеша?
post.body
задуманоcomment.body
?Ответы:
Для кеширования прямого дампа одного уже загруженного объекта, да, вы ничего не получаете или почти ничего. Это не то, что описывают эти примеры - они описывают иерархию, где любое изменение чего-то более низкого также должно вызывать обновление всего более высокого в иерархии.
Первый пример из блога 37signals использует
Project -> Todolist -> Todo
в качестве иерархии. Заполненный пример может выглядеть так:Итак, скажем,
Bang3
был обновлен. Все его родители также получают обновления:Затем, когда приходит время рендеринга, загрузка
Project
из базы данных в основном неизбежна. Вам нужно начать с. Однако, поскольку онlast_modified
является индикатором всех своих дочерних элементов , это то, что вы используете в качестве ключа кэша, прежде чем пытаться загрузить дочерние элементы.Хотя сообщения блога используют отдельные шаблоны, я собираюсь объединить их в один. Надеюсь, увидев полное взаимодействие в одном месте, станет немного понятнее.
Итак, шаблон Django может выглядеть примерно так:
Скажем , мы переходим в проекте которого до
cache_key
сих пор существует в кэше. Поскольку мы распространяем изменения на все связанные объекты на родительский объект, тот факт, что этот конкретный ключ все еще существует, означает, что все визуализированное содержимое может быть извлечено из кэша.Если этот конкретный проект был только что обновлен - например, как и
Foo
выше - тогда он должен будет отобразить своих потомков, и только тогда он выполнит запрос для всех Todolist для этого проекта. Аналогично для конкретного Todolist - если существует ключ cache_key этого списка, то задачи внутри него не изменились, и все это можно извлечь из кэша.Также обратите внимание, что я не использую
todo.cache_key
в этом шаблоне. Это того не стоит, так как, как вы говорите в вопросе,body
уже был извлечен из базы данных. Однако попадания в базу данных - не единственная причина, по которой вы можете что-то кэшировать. Например, взятие необработанного текста разметки (например, того, что мы вводим в поля вопросов / ответов в StackExchange) и преобразование его в HTML, может занять достаточно времени, чтобы кэширование результата было более эффективным.Если бы это было так, внутренний цикл в шаблоне мог бы выглядеть примерно так:
Итак, чтобы собрать все воедино, давайте вернемся к моим исходным данным в верхней части этого ответа. Если мы предположим:
Bang3
был только что обновленexpensive_markup_parser
)Тогда вот как все будет загружено:
Foo
извлекается из базы данныхFoo.cache_key
(2014-05-16) не существует в кешеFoo.todolists.all()
запрашивается:Bar1
иBar2
извлекается из базы данныхBar1.cache_key
(2014-05-10) уже существует в кэше ; получить и вывести егоBar2.cache_key
(2014-05-16) не существует в кешеBar2.todos.all()
запрашивается:Bang3
иBang4
извлекается из базы данныхBang3.cache_key
(2014-05-16) не существует в кеше{{ Bang3.body|expensive_markup_parser }}
оказываетсяBang4.cache_key
(2014-04-01) уже существует в кеше ; получить и вывести егоЭкономия от кэша в этом крошечном примере:
Bar1.todos.all()
expensive_markup_parser
избегали 3 раза:Bang1
,Bang2
иBang4
И, конечно, в следующий раз, когда он будет просмотрен,
Foo.cache_key
он будет найден, поэтому единственная стоимость рендеринга - это получение вFoo
одиночку из базы данных и запрос кеша.источник
Ваш пример хорош, если для каждого комментария требуется поиск или обработка данных. Если вы просто возьмете тело и отобразите его - кеш будет бесполезным. Но вы можете кэшировать все дерево комментариев (включая {% для%}). В этом случае вам нужно аннулировать его с каждым добавленным комментарием, чтобы вы могли поместить метку времени последнего комментария или счетчик комментариев где-нибудь в Post и построить ключ кеша комментариев с ним. Если вы предпочитаете более нормализованные данные и используете комментарии только на одной странице, вы можете просто очистить ключ кэша при сохранении комментария.
Для меня сохранение количества комментариев в Посте выглядит достаточно хорошо (если вы не разрешаете удалять и редактировать комментарии) - у вас есть значение, которое нужно показать где-либо с Постом, и ключ для кеширования.
источник