Django annotation,減少IO次數利器
annotation的中文含義是"註解"。正如這名字所暗示的,傳遞給annotate函式的每個引數,都會以"註解"的形式新增到model queryset返回的每一個object裡面。
和annotate經常在一起使用的是aggregation函式。
舉個栗子
Blog Model有一個外來鍵entry指向Entry model。我們想計算每個blog有多少個entry:
>>> from django.db.models import Count >>> q = Blog.objects.annotate(Count('entry')) # The name of the first blog >>> q[0].name 'Blogasaurus' # The number of entries on the first blog >>> q[0].entry__count 42 複製程式碼
我們一起break down上面這部分程式碼:
q = Blog.objects.annotate(Count('entry')) 複製程式碼
這裡使用了Count這個aggregation函式,作用是對一個指定的Blog object,計算它對應的Entry object有多少個。Blog.objects.annotate(Count('entry'))就是對每個Blog object,計算一下與之對應entry有幾個。返回值是一個queryset。與
Blog.objects.all() 複製程式碼
的區別在於,Blog.objects.annotate(Count('entry'))中的每一項,都多了一個entry__count欄位,這就是我們想要的那個資料。
q[0].name q[0].entry__count 複製程式碼
q是一個queryset,q[0]就是獲取第一個object,他裡面多了一個entry__count欄位。
舉個反栗子
如果你不知道annotate這個東西,你肯定會想到一種"pythonic"的方法:
q = Blog.objects.all() for blog in q: entry__count = blog.entry.count() print(blog.name) print(entry__count) 複製程式碼
這種方法更容易理解,但是會殺死你的效能。假如你有10W條blog,q = Blog.objects.all() 這裡進行了一次查詢,for迴圈那裡,對每一個blog都要進行一次查詢,所以總查詢次數是10W+1次,也就是那麼多次IO。而前面那種方法,總查詢次數只有一次,IO只有一次,計算entry的個數是在資料庫內容進行的,效率當然要高很多!
資料庫查詢有一個黃金原則: 儘可能減少IO次數 。而Python的for迴圈天然就會增加IO次數,所以,請擁抱annotation吧。
關注我的微信公眾號