select_related 方法
在常規models
操作中,某些對於關聯表的查詢稍有不慎可能導致產生多次查詢,如:
# views.py
from . import models
def test(request):
'''假設有一張user表,其關聯表為`usertype`,關聯欄位為`ut`
現在想要遍歷user表每一條資料
並查詢其關聯欄位`ut`所關聯表的對應`title`欄位
'''
# SELECT * FROM User
userlist = models.User.objects.all()
for row in userlist:
# SELECT title FROM usertype WHERE id=row.id
print('row.ut.title')
上面這種查詢操作會造成不必要的多次查詢,因為當userlist = models.User.objects.all()
執行時,取出來的資料包含了ut.id
但並不包含ut.title
,所以每次迴圈取值時都會去查詢關聯表的title
欄位。對此可以透過select_related
方法進行最佳化,該方法會將關聯表中的指定欄位一次查詢(即JOIN
查詢),從而避免產生多次查詢:
def test(request):
# SELECT * FROM User LEFT JOIN usertype on User.ut_id=usertype.id
userlist = models.User.objects.all().select_related('ut')
for row in userlist:
...
select_related
可以接收多個引數用於對多個關聯表的連表查詢。注意如果不需要對第三張表進行操作的話,則應該避免使用select_related
方法,因為連表查詢同樣消耗時間。
prefetch_related 方法
使用select_related
方法雖然能提升效能,但終究做了一次連表查詢,在同等條件下,連表查詢效能是低於單表查詢的。所以prefetch_related
就應運而生了。它會先執行子表的查詢,然後透過計算得出結果關鍵外來鍵的唯一值列表(可以理解為對所有關聯外來鍵進行set
操作去除重複值),然後透過IN
條件再從關聯表中查詢資料並放到記憶體中。示例如下:
models.UserInfo.objects.prefetch_related('ut')
# 先執行: SELECT * FROM UserInfo
# 透過計算獲取到所有使用者的使用者型別ID(ut的所有唯一值) [1, 2, 3]
# 最後執行: SELECT * FROM usertype WHERE id IN (1, 2, 3)
參考
- QuerySet API reference | Django 文件 | Django