2016-08-15 18 views
0

我有一個Django模型,其表中有數百萬條記錄。我正在嘗試對外殼中的表中的所有記錄執行一些緊急維護,但是我無法在不完全耗盡系統內存的情況下執行MyModel.objects.all()如何迭代Django中的大型表而不會耗盡內存?

即使pass導致OOM殺手被稱爲,殺死我的過程:

for ii in MyModel.objects.all(): 
    pass 

的原因是因爲Django的QuerySet正試圖建立自己的「結果緩存」,以建立一個列表與所有我在它的記錄,這裏

# django/db/models/query.py 
def _fetch_all(self): 
    if self._result_cache is None: 
     self._result_cache = list(self.iterator()) # <<<< this guy! 
    if self._prefetch_related_lookups and not self._prefetch_done: 
     self._prefetch_related_objects() 

但是我的機器不能保留在內存中的整個列表。

當然,在如此大的表格上迭代.all()在真實應用程序中會是一個糟糕的主意,所以這個問題的範圍相當有限(維護活動),但它確實時常出現。

回答

3

首先要嘗試使用的查詢集的iterator()方法迭代之前:

for ii in MyModel.objects.all().iterator(): 
+0

嗯,這確實出現了繞過結果緩存,但我仍然(在'Django的/ DB /後端/ utils.py'在'CursorWrapper.execute')運行內存.. 。所以我猜結果緩存不是唯一讓我難過的東西,它只是從postgres獲取的大量記錄... – mgalgs

+0

令我感到驚訝,但我還沒有深入到Django使用的細節遊標與將記錄拉入內存的位置。如果您可以在沒有實際模型實例的情況下進行維護,或者願意將原始數據庫記錄轉換爲模型,那麼從這個答案中鏈接的博客帖子可能會有幫助嗎? HTTP://計算器。com/questions/18381695/get-database-cursor-from-djangos-rawqueryset https://docs.djangoproject.com/en/1.10/topics/db/sql/#connections-and-cursors爲Django文檔。 –

+0

我在模型實例上調用方法,但我完全可以將這些工作分解出來,這是我希望避免的一些工作。這裏和那裏的奇怪維護並不是什麼大不了的事情。我只是希望有一個很好的方法可以做到這一點,而不必下降到原始數據庫記錄。好吧。 – mgalgs

0

您可能無法將所有完整記錄放入內存中,但很有可能您可以將所有主鍵都裝入內存中。所以,你可以遍歷所有的主鍵的列表,並做每一個.get()並在記錄上獨立地操作:

for pk in MyModel.objects.values_list('pk', flat=True): 
    ii = MyModel.objects.get(pk=pk) 
    ii.maintenance_activity() 

這是不是超級CPU效率,當然,但它更多的內存效率。鑑於這類事情只應用於維護活動,理想的性能不應該成爲問題。

0

如果您正在使用python3.X你可以嘗試一些異步任務。

創建計劃提取可能很有用。

事情是這樣的:

async def _fetch_all(self): 
    if self._result_cache is None: 
      self._result_cache = await list(self.iterator()) # <<<< this guy! 
    if self._prefetch_related_lookups and not self._prefetch_done: 
      await self._prefetch_related_objects() 

要運行代碼:

import asyncio 
my_model = MyModel() 
asyncio.get_event_loop().run_until_complete(my_model._fetch_all()) 

但如果你使用的是2.7,你將需要創建芹菜一個異步任務,或嘗試一些工具來做到這一點如Django Async

希望它有幫助。

Take a look

相關問題