使用Laravel将数据库导出为JSON超过内存限制



我有一个Laravel应用程序,它有一个带有长序列的底层数据库。我想为用户提供下载JSON格式数据库的机会。为此,我首先获取记录,然后将它们转换为JSON格式并写入文件。然而,当我将应用程序移动到生产服务器时,它给了我

You don't have permission to access /saveJson on this server.

从日志中,是错误消息:

[2021-01-07 19:08:50] local.ERROR: Allowed memory size of 1887436800 bytes exhausted (tried to allocate 675803754 bytes) {"userId":1,"exception":"[object] (Symfony\Component\Debug\Exception\FatalErrorException(code: 1): Allowed memory size of 1887436800 bytes exhausted (tried to allocate 675803754 bytes) at /home/xxx/vendor/league/flysystem/src/Util/MimeType.php:205)
[stacktrace]

服务器中的memory_limit已设置为-1,并在设置后重新启动。

代码的相关部分:

DB::connection()->disableQueryLog();
$large_db = Model::with('regions', 'genes.gene_models.aro_categories')
->where('curated', '<>', 4)
->get();
$db_JSON = $large_db->toJSON();
Storage::disk('public')->put("database_$date.json", $db_JSON);
DB::connection()->enableQueryLog();

根据MySQL的数据,整个数据库大约有170M,根据meminfo的数据,服务器有1962MB的内存,所以我不完全理解为什么它不能加载记录——尽管由于数据库会更新,我希望以一种不会在未来因类似原因崩溃的方式创建它。

有没有更聪明的方法可以在不超过内存限制的情况下导出数据库?某种缓冲?

谢谢你的建议!

toJSON()将模型转换为数组,然后使用PHP的原生json_encode()将数据转换为json。Laravel文档。

这个答案给出了使用json_encode()json_decode()在PHP数组和JSON之间移动的内存效率的估计。在回答者的计算中,PHP数组消耗的内存大约是JSON序列化数据的9倍。

用一种天真的方法来解决这个问题,我们可以假设我们需要大约是生成的JSON文件大小的10倍的内存来将数据转储到一个文件中(如果我们使用PHP数组(。

170MiB x 10已接近您的内存限制。包括Laravel对象中额外的内存开销在内,你正在耗尽所有可用内存是有道理的。

最好的选择是想出某种选项来转储数据库,从而跳过将数据库加载到PHP对象中。我建议编写一个MySQL查询,将JSON直接写入文件,然后返回生成的JSON文件。

最新更新