理解dajngo ORM查詢中select_related的作用
阿新 • • 發佈:2019-02-06
1. 我們基於以下模型來分析select_related的作用。
class Person(models.Model);
name = models.CharField(max_length=30)
age = models.IntegerField()
class Book(models.Model):
person = models.ForeignKey(Person)
title = models.CharField(max_length=50)
pubtime = models.DateField()
2. 模型結構為:
Book - title
- page
- person -> ForeignKey(Person)
3. 兩種查詢方式:
A. 不帶select_related
book = Book.objects.filter(pk=1) # 需要查詢資料庫 1
---------------------
result:
book - id
- title
- page
- Person.id
---------------------
n = book.name # 需要查詢資料庫 2
a = book.age # 需要查詢資料庫 3
*總共向資料庫發起三次查詢。
B. 帶select_related
book = Book.objects.select_related().filter(pk=1) # 需要查詢資料庫 1
---------------------
result:
book - id
- title
- page
- Person - id
- name
- age
---------------------
n = book.name # 直接從book物件中取
a = book.age # 直接從book物件中取
*總共向資料庫發起一次查詢。
也就是說使用select_related()
Book
關聯的物件都查詢出來放入物件中,再次查詢時就不需要再連線資料庫,節省了後面查詢資料庫的次數和時間。
4. depth引數
depth引數可以指定select_related(depth=2)
關聯的物件的層數,這裡就不作詳細解釋。
5. 指定關鍵字引數
指定關鍵字引數可以只查詢(join)指定的物件,節省資源。
book = Book.objects.select_related('person').filter(pk=1)
# 假設Person模型中有另外一個外來鍵city,可作如下查詢
book = Book.objects.select_related('person__city').filter(pk=1)
6. 參考
- select_related主要針一對一和多對一關係進行優化。
- select_related使用SQL的JOIN語句進行優化,通過減少SQL查詢的次數來進行優化、提高效能。
- 可以通過可變長引數指定需要select_related的欄位名。也可以通過使用雙下劃線“__”連線欄位名來實現指定的遞迴查詢。沒有指定的欄位不會快取,沒有指定的深度不會快取,如果要訪問的話Django會再次進行SQL查詢。
- 也可以通過depth引數指定遞迴的深度,Django會自動快取指定深度內所有的欄位。如果要訪問指定深度外的欄位,Django會再次進行SQL查詢。
- 也接受無引數的呼叫,Django會盡可能深的遞迴查詢所有的欄位。但注意有Django遞迴的限制和效能的浪費。
- Django >= 1.7,鏈式呼叫的select_related相當於使用可變長引數。Django < 1.7,鏈式呼叫會導致前邊的select_related失效,只保留最後一個。
更多文章可以訪問我的個人部落格:碼練