Django是一個基於Python的網站開發框架,一個很重要的特色就是Battery Included,簡單來講就是包含了常規開發中所須要的一切東西,包括但不限於完整的ORM模型、中間件、會話處理、模板語言、路由映射、管理員站點等,大大提升了開發者的開發體驗,今天要談的東西即是屬於Django ORM這塊中查詢集優化的內容。數據庫
在實際的開發中,模型之間常常存在複雜的關聯關係。在數據量較大的狀況下,默認的查詢可能面臨潛在的性能問題。今天咱們就分享一下Django ORM的查詢優化。框架
首先須要明確一點:post
Queryset是惰性求值的。性能
在Django中,全部的Queryset都是惰性的,意思是當建立一個查詢集的時候,並無跟數據庫發生任何交互。所以咱們能夠對查詢集進行級聯的filter等操做,只有在訪問Queryset的內容的時候,Django纔會真正進行數據庫的訪問。而多頻率、複雜的數據庫查詢每每是性能問題最大的根源。fetch
爲了方便說明,咱們定義如下model:優化
1 class A(models.Model): 2 foo = models.IntegerFiled() 3 4 class B(models.Model): 5 a = models.ForeignKey(A, related_name='bs')
關聯關係中,外鍵的查詢依然是惰性的。當咱們經過外鍵獲取一個關聯對象的時候,實際上默認獲取的是關聯對象的ID。這種狀況適用於只須要ID而不須要實際的關聯對象的場景,這點在Django的文檔中有相關說明:網站
If you only need a foreign key value, use the foreign key value that is already on the object you’ve got, rather than getting the whole related object and taking its primary key.spa
不過咱們實際開發中,每每須要訪問到外鍵對象的其餘屬性。若是按照默認的查詢方式去遍歷取值,那麼會形成屢次的數據庫查詢,效率可想而知。code
select_related和prefetch_related正是爲了解決這個問題,他們能夠達到這樣的目的:在查詢對象集合的時候,把指定的外鍵對象也一併完整查詢加載,避免後續的重複查詢。中間件
所以,咱們能夠經過下面的方式來獲取B的外鍵關係對象A的信息:
1 b = B.objects.select_related('a').all() 2 3 for temp_b in b: 4 print temp_b.a.foo
以上方式,實際上只會觸發一次數據庫查詢,會極大的提高查詢性能。
prefetch_related效果和select_related相似,不過使用的場景不一樣:
1,select_related適用於外鍵和多對一的關係查詢;
2,prefetch_related適用於一對多或者多對多的查詢。