Django的性能優化
一,利用標準數據庫優化技術
python
傳統數據庫優化技術博大精深,不一樣的數據庫有不一樣的優化技巧,但重心仍是有規則的。在這裏算是題外話,挑兩點通用的說說:
索引,給關鍵的字段添加索引,性能能更上一層樓,如給表的關聯字段,搜索頻率高的字段加上索引等。Django創建實體的時候,支持給字段添加索引,具體參考Django.db.models.Field.db_index。按照經驗,Django創建實體以前應該早想好表的結構,儘可能想到後面的擴展性,避免後面的表的結構變得面目全非。
使用適當字段類型,原本varchar就搞定的字段,就別要text類型,小細節別不關緊要,後頭數據量一上去,越來越多的數據,小字段極可能是大問題。數據庫
二 ,瞭解Django的QuerySets緩存
瞭解Django的QuerySets對象,對優化簡單程序有相當重要的做用。QuerySets是有緩存的,一旦取出來,它就會在內存裏呆上一段時間,儘可能重用它。性能優化
# 瞭解緩存屬性: >>> entry = Entry.objects.get(id=1) >>> entry.blog # 博客實體第一次取出,是要訪問數據庫的 >>> entry.blog # 第二次再用,那它就是緩存裏的實體了,再也不訪問數據庫
>>> entry = Entry.objects.get(id=1) >>> entry.authors.all() # 第一次all函數會查詢數據庫 >>> entry.authors.all() # 第二次all函數還會查詢數據庫
- all,count exists是調用函數(須要鏈接數據庫處理結果的),注意在模板template裏的代碼,模板裏不容許括號,但若是使用此類的調用函數,同樣去鏈接數據庫的,能用緩存的數據就別鏈接到數據庫去處理結果。還要注意的是,自定義的實體屬性,若是調用函數的,記得本身加上緩存策略。
- 利用好模板的with標籤:
模板中屢次使用的變量,要用with標籤,把它當作變量的緩存行爲吧。函數
- 使用QuerySets的iterator():
一般QuerySets先調用iterator再緩存起來,當獲取大量的實體列表而僅使用一次時,緩存行爲會耗費寶貴的內存,這時iterator()能幫到你,iterator()只調用iterator而省 去了緩存步驟,顯著減小內存佔用率,具體參考相關文檔。post
三, 數據庫的工做就交給數據庫自己計算,別用Python處理性能
- 使用 filter and exclude 過濾不須要的記錄,這兩個是最經常使用語句,至關是SQL的where
- 同一實體裏使用F()表達式過濾其餘字段
- 使用annotate對數據庫作聚合運算
不要用python語言對以上類型數據過濾篩選,一樣的結果,python處理複雜度要高,並且效率不高, 白白浪費內存fetch
- 使用QuerySet.extra() extra雖然擴展性不太好,但功能很強大,若是實體裏須要須要增長額外屬性,不得已時,經過extra來實現,也是個好辦法
- 使用原生的SQL語句 若是發現Django的ORM已經實現不了你的需求,而extra也無濟於事的時候,那就用原生SQL語句
四,若是須要就一次性取出你所須要的數據優化
單一動做(如:同一個頁面)須要屢次鏈接數據庫時,最好一次性取出全部須要的數據,減小鏈接數據庫次數。spa
此類需求推薦使用QuerySet.select_related() (主動連表)和 prefetch_related()(被動連表)
相反,別取出你不須要的東西,模版templates裏每每只須要實體的某幾個字段而不是所有,這時QuerySet.values() 和 values_list(),對你有用,它們只取你須要的字段,返回字典dict和列表list類型的東西,在模版裏夠用便可,這可減小內存損耗,提升性能
一樣QuerySet.defer()和only()對提升性能也有很大的幫助,一個實體裏可能有很多的字段,有些字段包含不少元數據,好比博客的正文,不少字符組成,Django獲取實體時(取出實體過程當中會進行一些python類型轉換工做),咱們能夠延遲大量元數據字段的處理,只處理須要的關鍵字段,這時QuerySet.defer()就派上用場了,在函數裏傳入須要延時處理的字段便可;而only()和defer()是相反功能
使用QuerySet.count()代替len(queryset),雖然這兩個處理得出的結果是同樣的,但前者性能優秀不少。同理判斷記錄存在時,QuerySet.exists()比if queryset實在強得太多了
五,懂減小數據庫的鏈接數
使用 QuerySet.update() 和 delete(),這兩個函數是能批處理多條記錄的,適當使用它們事半功倍;若是能夠,別一條條數據去update delete處理。
對於一次性取出來的關聯記錄,獲取外鍵的時候,直接取關聯表的屬性,而不是取關聯屬性,如:
entry.blog.id 優於 entry.blog__id # 善於使用批量插入記錄,如: Entry.objects.bulk_create([ Entry(headline="Python 3.0 Released"), Entry(headline="Python 3.1 Planned") ]) 優於 Entry.objects.create(headline="Python 3.0 Released") Entry.objects.create(headline="Python 3.1 Planned") # 前者只鏈接一次數據庫,然後者鏈接兩次 # 還有類似的動做須要注意的,如:多對多的關係, my_band.members.add(me, my_friend) 優於 my_band.members.add(me) my_band.members.add(my_friend)