Li recentemente um artigo no blog da 37Signals e fico me perguntando como é que eles obtêm a chave de cache.
É bom ter uma chave de cache que inclua o carimbo de data / hora do objeto (isso significa que quando você atualiza o objeto, o cache será invalidado); mas como você usa a chave de cache em um modelo sem causar um acerto no banco de dados para o mesmo objeto que você está tentando buscar no cache.
Especificamente, como isso afeta as relações Um para Muitos, nas quais você está processando os Comentários de uma Postagem, por exemplo.
Exemplo no Django:
{% for comment in post.comments.all %}
{% cache comment.pk comment.modified %}
<p>{{ post.body }}</p>
{% endcache %}
{% endfor %}
O cache no Rails é diferente de apenas solicitações para o memcached, por exemplo (eu sei que eles convertem sua chave de cache em algo diferente). Eles também armazenam em cache a chave de cache?
post.body
deveria sercomment.body
?Respostas:
Para armazenar em cache um despejo direto de um único objeto já carregado, sim, você ganha nada ou quase nada. Não é isso que esses exemplos estão descrevendo - eles estão descrevendo uma hierarquia, onde qualquer alteração em algo mais baixo também deve desencadear uma atualização para tudo o mais alto na hierarquia.
O primeiro exemplo, do blog 37signals, usa
Project -> Todolist -> Todo
como hierarquia. Um exemplo preenchido pode ser assim:Então, digamos que
Bang3
foi atualizado. Todos os seus pais também são atualizados:Então, quando chega a hora de renderizar, o carregamento
Project
do banco de dados é basicamente inevitável. Você precisa de um ponto para começar. No entanto, comolast_modified
é um indicador de todos os filhos , é isso que você usa como chave de cache antes de tentar carregar os filhos.Enquanto as postagens do blog usam modelos separados, vou agrupá-los em um. Esperamos que a interação completa em um só lugar a torne um pouco mais clara.
Portanto, o modelo do Django pode ser algo como isto:
Digamos que passamos em um projeto que
cache_key
ainda existe no cache. Como propagamos alterações em todos os objetos relacionados ao pai, o fato de essa chave específica ainda existir significa que todo o conteúdo renderizado pode ser extraído do cache.Se esse projeto em particular tivesse sido atualizado - por exemplo, como
Foo
acima -, ele precisará renderizar seus filhos e só então executará a consulta de todos os todolistas desse projeto. O mesmo vale para uma Todolist específica - se a cache_key dessa lista existir, todos os que estão nela não serão alterados e a coisa toda poderá ser extraída do cache.Observe também como não estou usando
todo.cache_key
neste modelo. Não vale a pena, pois, como você diz na pergunta,body
já foi extraído do banco de dados. No entanto, as ocorrências no banco de dados não são a única razão pela qual você pode armazenar algo em cache. Por exemplo, pegar texto de marcação bruto (como o que digitamos em caixas de perguntas / respostas no StackExchange) e convertê-lo em HTML pode levar tempo suficiente para que o armazenamento em cache do resultado seja mais eficiente.Se assim fosse, o loop interno no modelo pode parecer mais com isso:
Então, para juntar tudo, vamos voltar aos meus dados originais na parte superior desta resposta. Se assumirmos:
Bang3
foi atualizadoexpensive_markup_parser
)Então é assim que tudo seria carregado:
Foo
é recuperado do banco de dadosFoo.cache_key
(16/05/2014) não existe no cacheFoo.todolists.all()
é consultado:Bar1
eBar2
é recuperado do banco de dadosBar1.cache_key
(10/05/2014) já existe no cache ; recupere e produzaBar2.cache_key
(16/05/2014) não existe no cacheBar2.todos.all()
é consultado:Bang3
eBang4
é recuperado do banco de dadosBang3.cache_key
(16/05/2014) não existe no cache{{ Bang3.body|expensive_markup_parser }}
é processadoBang4.cache_key
(01/04/2014) já existe no cache ; recupere e produzaAs economias do cache neste pequeno exemplo são:
Bar1.todos.all()
expensive_markup_parser
evitados 3 vezes:Bang1
,Bang2
, eBang4
E, é claro, da próxima vez que for visualizado,
Foo.cache_key
será encontrado, portanto, o único custo para renderizar é recuperarFoo
sozinho do banco de dados e consultar o cache.fonte
Seu exemplo é bom se precisar de alguma recuperação ou processamento de dados para cada comentário. Se você pegar o corpo e exibi-lo, o cache será inútil. Mas você pode armazenar em cache todas as árvores de comentários (incluindo {% for%}). Nesse caso, é necessário invalidá-lo a cada comentário adicionado, para que você possa colocar o carimbo de data / hora do último comentário ou a contagem dos comentários em algum lugar no Post e criar a chave de cache de comentários com ele. Se você preferir dados mais normalizados e usar comentários em apenas uma página, basta limpar uma chave de cache ao salvar o comentário.
Para mim, salvar a contagem de comentários no Post parece bom o suficiente (se você não permitir excluir e editar comentários) - você tem um valor para mostrar em qualquer lugar com o Post e uma chave para o cache.
fonte