以更节省内存的方式操作大数组



我目前正在为一个应用程序编写一个API,该应用程序与大型数据库接口,需要从中检索大量数据,然后将其作为JSON吐出。

我正在使用CodeIgniter(CI(作为数据库接口,但我认为它在这里无关紧要。我遇到了内存限制,不幸的是,我无法增加限制,因为共享主机服务不会这样做。

我从数据库中获得了大约 56k 行,这些行被 CI(零索引,非常标准(放入数组中。每行有 7 个字段。

一切都很好,直到我开始循环遍历数组以修改数据。脚本在几次循环迭代后遇到内存限制错误,即使我只是修改原始数组,而不是分配新变量,我认为也是如此。

Allowed memory size of 134217728 bytes exhausted

以下是我正在使用的代码:

$query = $this->db->get('table');
if ($query->num_rows() > 0) {
$result = $query->result_array();
foreach ($result as $k => $v) {
foreach($v as $key => $value) {
if ($key === 'column_name') {
$result[$k][$key] = json_decode($value);
continue;
}
if ($value == null) {
$result[$k][$key] = '';
} else if (ctype_digit($value)) {
$result[$k][$key] = (int) $result[$k][$key];
}
}
}
return $result;
}

只是解码一些 json 并转换为整数或空字符串,没什么好看的。但是我会在任何改变$result数组的行上收到内存限制错误。即使我删除了(内存密集型(json_decode我仍然会在行上收到一个错误,该错误只是投射到int.

更重要的是,即使我删除了整个foreach,当我稍后使用json_encode生成 API 响应时,我会收到内存限制错误。

我完全迷失了,我真的需要一次输出这么多数据,不知道如何使其更节省内存(也许使用缓冲区之类的?从未深入研究过(。

编辑:对于任何感兴趣的人,我设法通过对数据库进行无缓冲查询来减少内存使用量。这样,数组中仅存储 1 个数据副本。我还删除了foreach并专门处理每个字段。然而,主要问题可能是PHP如何存储数组。下面是新代码:

$query = $this->db->get('table');
$result = [];
while ($row = $query->unbuffered_row('array')) {
if ($row['column1'] == '[]') {
$row['column1'] = [];
} else {
$row['column1'] = json_decode($row['column1']);
}
$row['column2'] = (int) $row['column2'];
$row['column3'] = (int) $row['column3'];
$row['column4'] = is_null($row['column4']) ? '' : (int) $row['column4'];
$row['column5'] = is_null($row['column5']) ? '' : (int) $row['column5'];
$result[] = $row;
}
return $result;

有很多方法可以解决这个问题,真正的问题是你的优先事项是什么?

  • 它必须快吗?它能慢吗?
  • 低内存服务器是绝对唯一可用的资源吗?

理想的解决方案显然是升级您的服务器,假设您的任务消耗大量内存,这应该是运行此项目的任何人关注的问题。

显然,使用微服务有现代方法可以做到这一点,每个微服务都处理一大块数据。它们可以由您编写,也可以使用AWS等云服务。

话虽如此,假设您确实仅限于当前的星座,并且您别无选择,只能使用有限的内存服务器来处理大数据,我建议您使用本地文件 I/O - 这不是最快的解决方案,但如果您读取数据块并继续将它们写入临时文件,您将节省内存问题, 然后,您可以将该文件刷新到客户端。

最新更新