2016-03-28 134 views
2

我有類似這樣的Django代碼:優化的Django得到查詢

for obj in some_list: 
    m1obj = Model1.objects.get(a=obj.a, b=obj.b, c=obj.c) 
    Model2(m1=m1obj, d=obj.d, e='foo').save() 

我並優化插入到使用bulk_createModel2,然而,這仍然是因爲getModel1〜45秒的痛苦而緩慢爲3k插入)。

我也嘗試添加:

class Meta: 
    index_together = [ 
     ('a', 'b', 'c'), 
    ] 
    unique_together = [ 
     ('a', 'b', 'c'), 
    ] 

unique_together幫助一點,index_together似乎並沒有產生太大的影響。

我對這個做了繁瑣的解決方法:

  1. 篩選Model1由一個或多個鍵讓我將需要訂購的所有對象,例如order_by('a', 'b'),並確保Django緩存結果,例如len()
  2. 使用二進制搜索(from bisect import bisect_left)來定位第一a然後b ...等(雖然也有少得多b S和c這麼只是迭代是一樣的。

這減少了插入時間強行超過3秒

必須有一個更好,更清潔和維護的方式來做到這一點。有什麼建議? 有沒有辦法來過濾/ Django的緩存查詢結果中獲得(瀟灑)?

編輯:更改d='foo'd=obj.d - 任何批量獲取需要映射到它所屬的元組,否則我不能創建Model2條目。

回答

0

您可以製作一個查詢(如描述here),該查詢僅提取您需要的結果,因此不需要稍後進行排序和二分查找。

我還沒有測試過,所以我不知道它是否會比你已經做或不做的更快。此外,由於SQL查詢將很大(根據some_list中的記錄數),因此如果該查詢超過MySQL設置中參數max_allowed_packet(默認情況下爲16MB,如here)中定義的大小,則此查詢可能會引發錯誤。

import operator 
from django.db.models import Q 
query = reduce(operator.or_, (Q(a=obj.a, b=obj.b, c=obj.c) for x in values)) 
model1_objs = Model1.objects.filter(query) 

然後,你可以做bulk_createModel2

Model2.objects.bulk_create([ 
    Model2(m1=m1, d='foo', e='bar') 
    for m1 in model1_objs 
]) 
+0

不幸的是,你的建議是不是做了'得到()'順序慢得多。 3分鐘後我停了下來。另外,正如我在編輯中提到的,如果參數'd'和'e'是常量,這可能(應該)已經工作。由於它們不是,我無法將'model1_objs'映射到正確的'obj.d',因爲數據庫查詢不能保證順序。 – mibm

0

Model1有多少行?如果它相對較小(小於50k),則可以使用篩選器獲取所有內容,然後在python中比較元組。

「some_list」如何是小列表(小於100),如果是,您可以使用Q關鍵字一次過濾所有內容。

first = some_list.pop() 
conditions = Q(a=first.a, b=first.b, c=first.c) 
for obj in some_list: 
    conditions |= Q(a=obj.a, b=obj.b, c=obj.c) 

Model1.objects.filter(conditions) # this will get your all the Model1 from ur list 

Q對象編號:https://docs.djangoproject.com/en/1.9/ref/models/querysets/#q-objects

+0

該解決方案與@ muhammad-tahir建議的相同。對於3K行,我在幾分鐘後殺死了查詢。對於較小的組,它不會比單獨的查詢更快(完全)。我確實改善了解決方法,爲表格行映射創建一個元組,以便快速且可讀,但如果行數爲100K而不是3K,則可能會遇到內存問題... – mibm