สำหรับการแคชดัมพ์ของวัตถุที่โหลดแล้วเดียวใช่แล้วคุณจะไม่ได้อะไรเลยหรือสิ่งที่ไม่ทำอะไรเลย นั่นไม่ใช่ตัวอย่างที่อธิบาย - พวกเขากำลังอธิบายลำดับชั้นที่การเปลี่ยนแปลงใด ๆ ที่ต่ำกว่าควรทำให้เกิดการอัปเดตทุกอย่างที่สูงกว่าในลำดับชั้น
ตัวอย่างแรกจากบล็อก 37signals ใช้Project -> Todolist -> Todo
เป็นลำดับชั้น ตัวอย่างที่มีประชากรอาจมีลักษณะเช่นนี้:
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)
ดังนั้นสมมติว่าBang3
มีการปรับปรุง ผู้ปกครองทั้งหมดได้รับการปรับปรุงด้วย:
Project: Foo (last_modified: 2014-05-16)
Todolist: Bar2 (last_modified: 2014-05-16)
Todo: Bang3 (last_modified: 2014-05-16)
จากนั้นเมื่อถึงเวลาที่ต้องแสดงผลการโหลดProject
จากฐานข้อมูลนั้นเป็นสิ่งที่หลีกเลี่ยงไม่ได้ คุณต้องมีจุดเริ่มต้น อย่างไรก็ตามเนื่องจากlast_modified
เป็นตัวบ่งชี้ถึงชายด์ทั้งหมดนั่นคือสิ่งที่คุณใช้เป็นคีย์แคชก่อนที่จะพยายามโหลดเด็ก ๆ
ในขณะที่โพสต์บล็อกใช้แม่แบบที่แยกจากกันฉันจะรวมเข้าด้วยกันเป็นหนึ่งเดียว หวังว่าการได้เห็นการโต้ตอบที่สมบูรณ์แบบในที่เดียวจะทำให้ชัดเจนขึ้น
ดังนั้นเทมเพลต Django อาจมีลักษณะเช่นนี้:
{% 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 %}
สมมติว่าเราผ่านโครงการที่cache_key
ยังคงมีอยู่ในแคช เนื่องจากเราเผยแพร่การเปลี่ยนแปลงวัตถุที่เกี่ยวข้องทั้งหมดไปยังผู้ปกครองความจริงที่ว่าคีย์เฉพาะยังคงมีอยู่หมายความว่าเนื้อหาที่แสดงผลทั้งหมดสามารถดึงจากแคช
หากโครงการนั้นเพิ่งได้รับการอัปเดต - ตัวอย่างเช่นเดียวกับFoo
ด้านบน - จากนั้นจะต้องแสดงผลลูกของมันและเฉพาะจากนั้นจะเรียกใช้แบบสอบถามสำหรับ Todolists ทั้งหมดสำหรับโครงการนั้น ในทำนองเดียวกันสำหรับ Todolist ที่เฉพาะเจาะจง - ถ้ารายการของแคชนั้นมีอยู่แล้วโทโปลภายในก็ไม่เปลี่ยนแปลงและสิ่งทั้งหมดสามารถดึงออกมาจากแคชได้
โปรดสังเกตว่าฉันไม่ได้ใช้todo.cache_key
งานแม่แบบนี้ด้วย มันไม่คุ้มค่าอย่างที่คุณพูดในคำถามเพราะbody
ถูกดึงออกมาจากฐานข้อมูลแล้ว อย่างไรก็ตามความนิยมของฐานข้อมูลไม่ใช่เหตุผลเดียวที่คุณอาจแคชบางสิ่ง ตัวอย่างเช่นการใช้ข้อความมาร์กอัปแบบดิบ (เช่นสิ่งที่เราพิมพ์ลงในกล่องคำถาม / คำตอบบน StackExchange) และการแปลงเป็น HTML อาจใช้เวลาเพียงพอที่การแคชผลลัพธ์จะมีประสิทธิภาพมากขึ้น
หากเป็นเช่นนั้นการวนซ้ำภายในในเทมเพลตอาจมีลักษณะเช่นนี้มากขึ้น:
{% for todo in list.todos.all %}
{% cache 9999 todo todo.cache_key %}
<li>{{ todo.body|expensive_markup_parser }}</li>
{% endcache %}
{% endfor %}
เพื่อดึงทุกอย่างเข้าด้วยกันลองกลับไปที่ข้อมูลดั้งเดิมของฉันที่ด้านบนของคำตอบนี้ หากเราถือว่า:
- วัตถุทั้งหมดถูกแคชในสถานะดั้งเดิม
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
เดียวคือการดึงข้อมูลเพียงอย่างเดียวจากฐานข้อมูลและทำการแคช