SQL Debug日志開啟

LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
select_related(*fields)
返回一個QuerySet,當執行它的查詢時它沿着外鍵關系查詢關聯的對象的數據。它會生成一個復雜的查詢並引起性能的損耗,但是在以后使用外鍵關系時將不需要數據庫查詢。
***對於一對一字段(OneToOneField)和外鍵字段(ForeignKey),可以使用select_related 來對QuerySet進行優化,在對QuerySet使用select_related()函數后,Django會獲取相應外鍵對應的對象,從而在之后需要的時候不必再查詢數據庫了。
示例1:
標准的查詢:
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
select_related查詢:
# Hits the database. e = Entry.objects.select_related('blog').get(id=5) # Doesn't hit the database, because e.blog has been prepopulated # in the previous query. b = e.blog
示例二:
Host.objects.select_related("business").filter(user__username=user_name).count()
小結
1.select_related主要針一對一和多對一關系進行優化。
2.select_related使用SQL的JOIN語句進行優化,通過減少SQL查詢的次數來進行優化、提高性能。
3.可以通過可變長參數指定需要select_related的字段名。也可以通過使用雙下划線“__”連接字段名來實現指定的遞歸查詢。沒有指定的字段不會緩存,沒有指定的深度不會緩存,如果要訪問的話Django會再次進行SQL查詢。
4.也可以通過depth參數指定遞歸的深度,Django會自動緩存指定深度內所有的字段。如果要訪問指定深度外的字段,Django會再次進行SQL查詢。
5.也接受無參數的調用,Django會盡可能深的遞歸查詢所有的字段。但注意有Django遞歸的限制和性能的浪費。
prefetch_related(*lookups)
這允許它預取多對多和多對一對象,因為它們不能使用select_related來完成。
*** select_related主要是執行跨表操作,而prefetch_related不是跨表操作,而是對每個表分別執行SQL查詢(Django內部在您使用時自動會幫你像跨表操作一樣連接起來),從而減少跨表查詢,提升性能。
小結
- 因為select_related()總是在單次SQL查詢中解決問題,而prefetch_related()會對每個相關表進行SQL查詢,因此select_related()的效率通常比后者高。
- 鑒於第一條,盡可能的用select_related()解決問題。只有在select_related()不能解決問題的時候再去想prefetch_related()。
- 你可以在一個QuerySet中同時使用select_related()和prefetch_related(),從而減少SQL查詢的次數。
- 只有prefetch_related()之前的select_related()是有效的,之后的將會被無視掉。
理解緩存屬性
和整個QuerySet的緩存相同,ORM對象的屬性的結果中也存在緩存。通常來說,不可調用的屬性會被緩存。例如下面的博客模型示例:
>>> entry = Entry.objects.get(id=1) >>> entry.blog # Blog object is retrieved at this point
>>> entry.blog # cached version, no DB access
但是通常來講,可調用的屬性每一次都會訪問數據庫。
>>> entry = Entry.objects.get(id=1) >>> entry.authors.all() # query performed
>>> entry.authors.all() # query performed again
使用iterator()
當你有很多對象時,QuerySet的緩存行為會占用大量的內存。這種情況下,采用iterator()解決。
用唯一的被索引的列來檢索獨立對象
有兩個原因在get()中,用帶有unique或者db_index的列檢索獨立對象。首先,由於查詢經過了數據庫的索引,所以會更快。其次,如果很多對象匹配查詢,查詢會更慢一些;列上的唯一性約束確保這種情況永遠不會發生。
使用QuerySet.values()和values_list()
當你僅僅想要一個帶有值的字典或者列表,並不需要使用ORM模型對象時,可以適當使用values()。對於在模板代碼中替換模型對象,這樣會非常有用 —— 只要字典中帶有的屬性和模板中使用的一致,就沒問題。
使用QuerySet.defer()和only()
如果一些數據庫的列你並不需要(或者大多數情況下並不需要),使用defer()和only()來避免加載它們。注意如果你確實要用到它們,ORM會在另外的查詢之中獲取它們。如果你不能夠合理地使用這些函數,不如不用。
使用QuerySet.count()
...如果你想要獲取大小,不要使用 len(queryset)。
使用QuerySet.exists()
...如果你想要知道是否存在至少一個結果,不要使用if queryset。
user_obj = UserInfo.objects.filter(username=login_obj.cleaned_data["login_username"], password=login_obj.cleaned_data["login_password"]) if user_obj.exists(): return HttpResponse(json.dumps(response))
直接使用外鍵的值
如果你僅僅需要外鍵當中的一個值,要使用對象上你已經取得的外鍵的值,而不是獲取整個關聯對象再得到它的主鍵。例如,執行:
entry.blog_id
而不是:
entry.blog.id
整體插入
創建對象時,盡可能使用bulk_create()來減少SQL查詢的數量。例如:
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")
這也可以用在ManyToManyFields中,所以:
my_band.members.add(me, my_friend)
...更優於:
my_band.members.add(me)
my_band.members.add(my_friend)
使用QuerySet.update()和delete()
通過QuerySet.update()使用批量的SQL UPDATE語句,而不是獲取大量對象,設置一些值再單獨保存。與此相似,在可能的地方使用批量deletes。
1111