1. 程式人生 > >理解dajngo ORM查詢中select_related的作用

理解dajngo ORM查詢中select_related的作用

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. 參考

  1. select_related主要針一對一和多對一關係進行優化。
  2. select_related使用SQL的JOIN語句進行優化,通過減少SQL查詢的次數來進行優化、提高效能。
  3. 可以通過可變長引數指定需要select_related的欄位名。也可以通過使用雙下劃線“__”連線欄位名來實現指定的遞迴查詢。沒有指定的欄位不會快取,沒有指定的深度不會快取,如果要訪問的話Django會再次進行SQL查詢。
  4. 也可以通過depth引數指定遞迴的深度,Django會自動快取指定深度內所有的欄位。如果要訪問指定深度外的欄位,Django會再次進行SQL查詢。
  5. 也接受無引數的呼叫,Django會盡可能深的遞迴查詢所有的欄位。但注意有Django遞迴的限制和效能的浪費。
  6. Django >= 1.7,鏈式呼叫的select_related相當於使用可變長引數。Django < 1.7,鏈式呼叫會導致前邊的select_related失效,只保留最後一個。

更多文章可以訪問我的個人部落格:碼練