Za buforowanie prostego zrzutu pojedynczego, już załadowanego obiektu, tak, nie zyskujesz nic lub prawie nic. Nie tak opisują te przykłady - opisują hierarchię, w której każda zmiana czegoś niższego powinna również spowodować aktualizację wszystkiego wyżej w hierarchii.
Pierwszy przykład z bloga 37signals używa Project -> Todolist -> Todo
jako hierarchii. Wypełniony przykład może wyglądać następująco:
Project: Foo (last_modified: 2014-05-10)
Todolist: Bar1 (last_modified: 2014-05-10)
Todo: Bang1 (last_modified: 2014-05-09)
Todo: Bang2 (last_modified: 2014-05-09)
Todolist: Bar2 (last_modified: 2014-04-01)
Todo: Bang3 (last_modified: 2014-04-01)
Todo: Bang4 (last_modified: 2014-04-01)
Powiedzmy, że Bang3
został zaktualizowany. Wszyscy jego rodzice również zostaną zaktualizowani:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
Jeśli chodzi o czas renderowania, ładowanie Project
z bazy danych jest w zasadzie nieuniknione. Musisz zacząć od punktu. Ponieważ last_modified
jest to wskaźnik wszystkich jego elementów podrzędnych , właśnie tego używasz jako klucza pamięci podręcznej przed próbą załadowania elementów podrzędnych.
Podczas gdy posty na blogu używają oddzielnych szablonów, połączę je w jeden. Mam nadzieję, że zobaczenie pełnej interakcji w jednym miejscu sprawi, że będzie trochę jaśniej.
Szablon Django może więc wyglądać mniej więcej tak:
{% cache 9999 project project.cache_key %}
<h2>{{ project.name }}<h2>
<div>
{% for list in project.todolist.all %}
{% cache 9999 todolist list.cache_key %}
<ul>
{% for todo in list.todos.all %}
<li>{{ todo.body }}</li>
{% endfor %}
</ul>
{% endcache %}
{% endfor %}
</div>
{% endcache %}
Powiedzmy, że przekazujemy projekt, który cache_key
nadal istnieje w pamięci podręcznej. Ponieważ propagujemy zmiany do wszystkich powiązanych obiektów do elementu nadrzędnego, fakt, że ten konkretny klucz nadal istnieje, oznacza, że całą renderowaną zawartość można pobrać z pamięci podręcznej.
Jeśli ten konkretny projekt został właśnie zaktualizowany - na przykład tak jak Foo
powyżej - wówczas będzie musiał renderować swoje dzieci, i dopiero wtedy uruchomi zapytanie dla wszystkich Todolists dla tego projektu. Podobnie w przypadku konkretnego Todolisty - jeśli istnieje klucz cache tej listy, to todos w nim się nie zmieniły, a całość można wyciągnąć z bufora.
Zauważ też, że nie używam todo.cache_key
tego szablonu. Nie warto, ponieważ, jak mówisz w pytaniu, body
zostało już usunięte z bazy danych. Jednak trafienia do bazy danych nie są jedynym powodem, dla którego możesz buforować coś. Na przykład pobranie surowego tekstu znaczników (takiego jak to, co wpisujemy w polach pytań / odpowiedzi na StackExchange) i konwersja go do HTML może zająć wystarczająco dużo czasu, aby buforowanie wyniku było bardziej wydajne.
Gdyby tak było, wewnętrzna pętla w szablonie mogłaby wyglądać mniej więcej tak:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
Aby więc zebrać wszystko w całość, wróćmy do moich oryginalnych danych na początku tej odpowiedzi. Jeśli założymy:
- Wszystkie obiekty zostały zbuforowane w oryginalnym stanie
Bang3
został właśnie zaktualizowany
- Renderujemy zmodyfikowany szablon (w tym
expensive_markup_parser
)
W ten sposób wszystko zostanie załadowane:
Foo
jest pobierany z bazy danych
Foo.cache_key
(2014-05-16) nie istnieje w pamięci podręcznej
Foo.todolists.all()
jest pytany: Bar1
i Bar2
są pobierane z bazy danych
Bar1.cache_key
(2014-05-10) już istnieje w pamięci podręcznej ; pobierz i wyślij go
Bar2.cache_key
(2014-05-16) nie istnieje w pamięci podręcznej
Bar2.todos.all()
jest pytany: Bang3
i Bang4
są pobierane z bazy danych
Bang3.cache_key
(2014-05-16) nie istnieje w pamięci podręcznej
{{ Bang3.body|expensive_markup_parser }}
jest renderowane
Bang4.cache_key
(2014-04-01) już istnieje w pamięci podręcznej ; pobierz i wyślij go
Oszczędności z pamięci podręcznej w tym niewielkim przykładzie to:
- Uniknięto trafienia bazy danych:
Bar1.todos.all()
expensive_markup_parser
unikać 3 razy: Bang1
, Bang2
, iBang4
I oczywiście przy następnym wyświetleniu Foo.cache_key
zostanie znaleziony, więc jedynym kosztem renderowania jest Foo
samodzielne pobieranie z bazy danych i sprawdzanie pamięci podręcznej.