Hace poco leí un artículo en el blog 37Signals y me pregunto cómo es que obtienen la clave de caché.
Está muy bien tener una clave de caché que incluya la marca de tiempo del objeto (esto significa que cuando actualice el objeto, la caché se invalidará); pero, ¿cómo se usa la clave de caché en una plantilla sin causar un golpe de base de datos para el objeto que está tratando de recuperar de la caché?
Específicamente, ¿cómo afecta esto a las relaciones de uno a muchos, por ejemplo, cuando representa los comentarios de una publicación?
Ejemplo en Django:
{% for comment in post.comments.all %}
{% cache comment.pk comment.modified %}
<p>{{ post.body }}</p>
{% endcache %}
{% endfor %}
El almacenamiento en caché en Rails es diferente a las solicitudes de memcached, por ejemplo (sé que convierten su clave de caché en algo diferente). ¿También guardan en caché la clave de caché?

post.bodydestinado a sercomment.body?Respuestas:
Para almacenar en caché un volcado directo de un solo objeto ya cargado, sí, no gana nada o casi nada. Eso no es lo que esos ejemplos están describiendo: están describiendo una jerarquía, donde cualquier cambio a algo más bajo también debería desencadenar una actualización de todo lo que está más arriba en la jerarquía.
El primer ejemplo, del blog 37signals, se usa
Project -> Todolist -> Todocomo jerarquía. Un ejemplo poblado podría verse así:Entonces, digamos que
Bang3se actualizó. Todos sus padres también se actualizan:Luego, cuando llega el momento de renderizar, la carga
Projectdesde la base de datos es básicamente inevitable. Necesitas un punto para comenzar. Sin embargo, debido a quelast_modifiedes un indicador de todos sus elementos secundarios , eso es lo que utiliza como clave de caché antes de intentar cargar los elementos secundarios.Si bien las publicaciones del blog usan plantillas separadas, las agruparé en una sola. Con suerte, ver la interacción completa en un lugar lo hará un poco más claro.
Entonces, la plantilla de Django podría verse así:
Digamos que pasamos un proyecto cuyo
cache_keytodavía existe en el caché. Debido a que propagamos los cambios a todos los objetos relacionados al padre, el hecho de que esa clave en particular aún exista significa que todo el contenido renderizado se puede extraer de la memoria caché.Si ese Proyecto en particular acaba de actualizarse, por ejemplo, como en el caso
Fooanterior, tendrá que representar a sus hijos, y solo entonces ejecutará la consulta para todos los Todolistas para ese Proyecto. Del mismo modo para un Todolist específico: si la clave_caché de esa lista existe, entonces los todos dentro de ella no han cambiado, y todo se puede extraer de la caché.Observe también cómo no estoy usando
todo.cache_keyen esta plantilla. No vale la pena, ya que como dices en la pregunta,bodyya se ha retirado de la base de datos. Sin embargo, los accesos a la base de datos no son la única razón por la que puede almacenar algo en caché. Por ejemplo, tomar texto de marcado sin formato (como lo que escribimos en los cuadros de preguntas / respuestas en StackExchange) y convertirlo a HTML puede llevar suficiente tiempo para que el resultado del almacenamiento en caché sea más eficiente.Si así fuera, el bucle interno de la plantilla podría verse más así:
Entonces, para reunir todo, volvamos a mis datos originales en la parte superior de esta respuesta. Si suponemos:
Bang3acaba de actualizarseexpensive_markup_parser)Entonces así es como se cargaría todo:
Foose recupera de la base de datosFoo.cache_key(2014-05-16) no existe en el cachéFoo.todolists.all()se consulta:Bar1yBar2se recuperan de la base de datosBar1.cache_key(2014-05-10) ya existe en el caché ; recuperarlo y sacarloBar2.cache_key(2014-05-16) no existe en el cachéBar2.todos.all()se consulta:Bang3yBang4se recuperan de la base de datosBang3.cache_key(2014-05-16) no existe en el caché{{ Bang3.body|expensive_markup_parser }}se representaBang4.cache_key(2014-04-01) ya existe en el caché ; recuperarlo y sacarloLos ahorros del caché en este pequeño ejemplo son:
Bar1.todos.all()expensive_markup_parserevitadas 3 veces:Bang1,Bang2yBang4Y, por supuesto, la próxima vez que
Foo.cache_keyse vea , se encontrará, por lo que el único costo para renderizar es recuperarFoosolo de la base de datos y consultar el caché.fuente
Su ejemplo es bueno si necesita un poco de recuperación o procesamiento de datos para cada comentario. Si solo toma el cuerpo y lo muestra, el caché será inútil. Pero puede almacenar en caché todos los árboles de comentarios (incluido {% para%}). En este caso, debe invalidarlo con cada comentario agregado, para que pueda colocar la marca de tiempo del último comentario o el recuento de comentarios en algún lugar en Publicar y construir una clave de caché de comentarios con él. Si prefiere datos más normalizados y usa comentarios en una sola página, puede borrar una clave de caché al guardar comentarios.
Para mí, guardar el recuento de comentarios en la publicación se ve lo suficientemente bueno (si no permite eliminar y editar comentarios): tiene un valor para mostrar en cualquier lugar con la publicación y una clave para el almacenamiento en caché.
fuente