Python Django加载数据-内存不足
我使用创建了一个500mb json文件来转储我的db 现在我正试图使用恢复数据库,但Django似乎试图在应用它之前将整个文件加载到内存中,结果出现内存不足错误,进程被终止Python Django加载数据-内存不足,python,django,database-restore,Python,Django,Database Restore,我使用创建了一个500mb json文件来转储我的db 现在我正试图使用恢复数据库,但Django似乎试图在应用它之前将整个文件加载到内存中,结果出现内存不足错误,进程被终止 没有办法绕过这个问题吗?loaddata通常用于固定装置,即少量数据库对象用于启动系统和进行测试,而不是用于大块数据。如果您达到了内存限制,那么您可能没有将其用于正确的目的 如果您仍然拥有原始数据库,那么应该使用更适合此目的的数据库,如PostgreSQL的pg_dump或MySQL的mysqldump,正如Joe指出的,
没有办法绕过这个问题吗?
loaddata
通常用于固定装置,即少量数据库对象用于启动系统和进行测试,而不是用于大块数据。如果您达到了内存限制,那么您可能没有将其用于正确的目的
如果您仍然拥有原始数据库,那么应该使用更适合此目的的数据库,如PostgreSQL的
pg_dump
或MySQL的mysqldump
,正如Joe指出的,PostgreSQL的pg_dump或MySQL的mysqldump更适合您的情况
如果您丢失了原始数据库,有两种方法可以尝试恢复数据:
第一:找到另一台有更多内存并且可以访问数据库的机器。在该计算机上构建项目,并在该计算机上运行loaddata命令
我知道这听起来很傻。但是,如果您可以在笔记本电脑上运行django,并且可以远程连接到db,那么这是最快的方法
第二:破解Django源代码
检查django.core.erializers.json.py中的代码:
def Deserializer(stream_or_string, **options):
"""
Deserialize a stream or string of JSON data.
"""
if not isinstance(stream_or_string, (bytes, six.string_types)):
stream_or_string = stream_or_string.read()
if isinstance(stream_or_string, bytes):
stream_or_string = stream_or_string.decode('utf-8')
try:
objects = json.loads(stream_or_string)
for obj in PythonDeserializer(objects, **options):
yield obj
except GeneratorExit:
raise
except Exception as e:
# Map to deserializer error
six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])
下面的代码就是问题所在。stdlib中的json
模块只接受字符串,不能延迟处理流。因此django将json文件的所有内容加载到内存中
stream_or_string = stream_or_string.read()
objects = json.loads(stream_or_string)
您可以使用。py yajl使用yajl创建内置json.load和json.dump的替代方案 我在将数据从Microsoft SQL Server迁移到PostgreSQL时遇到了这个问题,因此
sqldump
和pg_dump
不是我的选择。我将json装置分割成适合内存的块(对于宽表和64GB ram,大约有1M行)
然后,您可以使用
manage.py loaddata加载它们。这是一个FOSS python包,包含类似的黑客工具,用于处理django中的大型迁移和数据挖掘任务。我想补充一点,我在ijson的类似用例中非常成功:
为了从django dumpdata获得json文件中对象的迭代器,我修改了json反序列化程序,如下所示(省略导入):
按原样使用py-yajl的问题是,您仍然可以在一个大数组中获取所有对象,这会占用大量内存。此循环仅使用与单个序列化Django对象相同的内存。此外,ijson仍然可以使用yajl作为后端。您可以使用XML格式进行序列化/反序列化。它是通过文件流在内部实现的,与JSON相比不需要太多内存。不幸的是,Django JSON反序列化不使用流
所以,试试看:
./manage.py dumpdata file.xml
然后
./manage.py loaddata file.xml
由于对某些字段应用了限制,因此在pg_dump
/pg_restore
方面也存在问题
在我的例子中,我通过zappa在aws lambda上运行django,并希望迁移到aurora serverless(postgres)。我从bastion t2.micro实例生成了dumpdata文件,但是当我尝试加载数据时,该微实例没有足够的内存,并且该进程被os on loaddata尝试杀死
因此,我需要对数据进行分块,以便可以在实例的内存中对其进行处理,并且由于字段限制,需要按特定顺序加载记录。(如果没有,我会得到链接记录不存在的错误)
下面是我的脚本,用于对dumpdata进行分块,并按顺序将其分块,以便在没有约束相关错误的情况下成功加载:
注意:这是在具有足够内存的机器上准备的,以便在内存中保存所有数据。因此,该脚本的结果在创建后被传输到t2.micro
实例,其中loaddata按结果顺序运行
导入json
从输入导入列表开始
从集合导入计数器,defaultdict
从pathlib导入路径
工作目录=Path.home()/“migratedb”
dumpdata\u filepath=working\u directory/'db\u backup\u 20190830.json'
def chunk_dumpdata_json(dumpdata_filepath:Path,app_model_order:List):
文件\创建\顺序=[]
最大块记录数=25000
使用dumpdata\u filepath。在以下位置以数据\u的形式打开('r'):
all_data=json.load(data_in.read())
打印(f'记录计数:{len(所有数据)}')
model_records=defaultdict(列表)
对于总计数,在枚举中记录(所有数据):
app_model_name=记录['model']
在app_model_order中断言app_model_name,f'{app_model_name}不在:{app_model_order}
模型记录[应用程序模型名称].追加(记录)
#按模型顺序分组
总记录计数=0
chunks=defaultdict(列表)
对于应用程序模型订单中的应用程序模型:
对于模型\记录中的记录[应用\模型]:
记录块=总记录块计数-(总记录块计数%max\u块记录)
块[record_chunk]。追加(记录)
总记录计数+=1
对于chunk,以chunk.items()为单位记录:
chunk_filename=f'dumpdata_v1_chunk{chunk}.json'
chunk\u filepath=工作目录/chunk\u文件名
打印(chunk\u filepath.name)
文件\u创建\u顺序.append(chunk\u filepath.name)
将chunk_filepath.open('w',encoding='utf8')作为输出:
out.write(json.dumps(记录))
返回文件\u创建\u顺序
应用程序\型号\订单=(
'应用程序模型1',
'app.model2',
)
结果\文件\创建\顺序=区块\转储数据\ json(转储数据\文件路径、应用\模型\顺序)
然后我获取下面脚本的输出,将其保存到loaddata.sh
并运行它:
for item in result_file_creation_order:
if item:
print(f'echo "Loading {item} ..."')
print(f'python manage.py loaddata ~/migrationdata/{item}')
你的dj是什么
./manage.py dumpdata file.xml
./manage.py loaddata file.xml
for item in result_file_creation_order:
if item:
print(f'echo "Loading {item} ..."')
print(f'python manage.py loaddata ~/migrationdata/{item}')