Bel*_*dar 5 python django postgresql
我有大约40万个对象实例插入postgres.我正在使用bulk_create()来执行此操作,但我遇到了内存错误.
我的第一个想法是将实例列表分块:
def chunks(l, n):
n = max(1, n)
return [l[i:i + n] for i in range(0, len(l), n)]
for c in chunks(instances, 1000):
Feature.objects.bulk_create(c)
Run Code Online (Sandbox Code Playgroud)
但有时候这种策略也会导致内存错误,因为实例的大小可能会有很大变化,因此一个块可能会超出内存限制,而其他的则不会.
是否可以将实例列表分块以获得分隔大小的块?在这种情况下,最好的方法是什么?
lin*_*nqu 11
如果您在调试模式下使用Django,它将跟踪所有sql状态,以进行调试.对于许多对象,这可能会导致内存问题.你可以用以下方法重置:
from django import db
db.reset_queries()
Run Code Online (Sandbox Code Playgroud)
如果您没有以调试模式运行,并且仍然有错误,我的解决方案应该可以帮助您。首先,确保您有一组要保存的延迟生成的对象(例如,批量从远程 API 获取)
def generate_data():
"""Example data generator"""
for i in range(100000):
yield Model(counter=i)
data_gen = generate_data()
# >> print data_gen
# <generator object data at 0x7f057591c5c8>
#
# it's a generator, objects are not yet created.
# You can iterate it one-by-one or force generation using list(data_gen)
# But for our approach, we need generator version
Run Code Online (Sandbox Code Playgroud)
接下来,我们需要一个函数,它一次从该生成器中获取最多 X 个对象并使用 保存它batch_create。这样,在某一时刻我们将在内存中保存不超过 X 个对象。
from itertools import islice
def bulk_create_iter(iterable, batch_size=10000):
"""Bulk create supporting generators. Returns only count of created objects."""
created = 0
while True:
objects = Model.bulk_create(islice(iterable, batch_size))
created += len(objects)
if not objects:
break
return created
Run Code Online (Sandbox Code Playgroud)
并像这样使用它
print(bulk_create_iter(data_gen))
# prints 100000
Run Code Online (Sandbox Code Playgroud)
不能直接使用的原因batch_create是它在内部正在执行list(objs),因此整个生成器被实例化并保存到内存中。在这种方法中,我们batch_size一次实例化最多的对象。此方法甚至可以用于处理非常大的集合,因为内存消耗应该是恒定的(使用 15 000 000 条记录进行测试,内存使用量始终低于 300MB)。
准备使用此函数的通用版本,作为 DjangoManager类的方法(您可以通过编写在模型中使用它objects = BulkManager()):
from itertools import islice
from django.db import models
class BulkManager(models.Manager):
def bulk_create_iter(self, iterable, batch_size=10000):
"""Bulk create supporting generators, returns number of created objects."""
created = 0
while True:
objects = self.bulk_create(islice(iterable, batch_size))
created += len(objects)
if not objects:
break
return created
Run Code Online (Sandbox Code Playgroud)
您可以在bulk_create方法中指定batch_size。
Syntax: bulk_create(objs, batch_size=None)
Feature.objects.bulk_create(instances, batch_size=1000)
Run Code Online (Sandbox Code Playgroud)
https://docs.djangoproject.com/zh-CN/1.7/ref/models/querysets/#bulk-create
| 归档时间: |
|
| 查看次数: |
4455 次 |
| 最近记录: |