2017-03-07 62 views
1

我使用Django 1.9.10:爲什麼Django MultipleObjectsReturned錯誤佔用內存?

我有一個名爲Details模型具有unique_id列被編入索引:

try: 
    detail = Detail.objects.get(unique_id=UUID) 
except MultipleObjectsReturned as m: 
    logger.error("uuid {} returned multiple objects - {}".format(UUID, str(m))) 

由於一些錯誤代碼UUID=None這導致越來越引發MultipleObjectsReturned錯誤。但我們注意到幾乎2GB的內存已經用完了,並且使系統速度下降很多。

在錯誤日誌中,我們發現印刷STR(米)以下錯誤

MultipleObjectsReturned:get()方法返回一個以上的詳細信息 - 它返回451424!

我的問題是爲什麼Django在內存中提取這麼多數據只是爲了引發錯誤? Django可以取數?

我知道我可以使用filter()來解決這個問題,但我只是爲此感到驚訝,並且想明白爲什麼django會這樣做?

回答

3

因爲這是它是如何在內部完成:

def get(self, *args, **kwargs): 
    """ 
    Perform the query and return a single object matching the given 
    keyword arguments. 
    """ 
    clone = self.filter(*args, **kwargs) # calling `filter()` inside 
    if self.query.can_filter() and not self.query.distinct_fields: 
     clone = clone.order_by() 
    num = len(clone) 
    if num == 1: 
     return clone._result_cache[0] 
    if not num: 
     raise self.model.DoesNotExist(
      "%s matching query does not exist." % 
      self.model._meta.object_name 
     ) 
    raise self.model.MultipleObjectsReturned(
     "get() returned more than one %s -- it returned %s!" % 
     (self.model._meta.object_name, num) 
    ) 

查看完整的源here

我想你想知道爲什麼它不能只取數字?因爲它會向數據庫發出兩個請求,而不是一個。一次獲取計數和一次請求獲取數據的請求。

你怎麼解決它?您可以更改您的應用程序邏輯以避免這種情況。斷言UUID不是None。或者在進行實際查詢之前取count

文檔約gethttps://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-a-single-object-with-get

+0

用過濾器查詢上的limit()修改get()是不是個好主意。然後只是說get()返回多個結果,跳過計數部分並避免因爲沒有將太多記錄帶入內存而導致系統崩潰 – Crazyshezy

+0

@Crazyshezy你可以提交一個票據和一個補丁到Django項目,如果你認爲它是一個寶貴的改進。 –

+1

@Crazyshezy所以這很有趣。在1.7中,他們有你在推薦的限制。不知道他們爲什麼後來刪除它。在https://github.com/django/django/blob/stable/1.7.x/django/db/models/query.py查看代碼 – saurabh

0

因爲你有更多的數據庫中有相同的ID。 重寫查詢到這一點:Detail.objects.filter(unique_id=UUID)

1

因爲你用不用彷徨,當你知道你不應該得到多個對象。

選擇在451424項目被返回的情況下使用它並不是它的設計目的。

相關問題