我在 PHP 中使用了一个 80k x 20 的整数值矩阵(数组),内存不足。有解决办法吗?
背景
我有一个收集数据并将其存储到数据库的 PHP 应用程序。数据收集在不同的域 (>20k)。变量的数量在整个域中有所不同(主要是无限的),所以我必须在我的 MySQL 数据库中存储逗号分隔的列表(在版本 5 之前)。这表现相当不错。
在某个时间点,用户需要下载数据。下载功能必须执行一些标准化,因此它需要每个变量的中位数(不是平均值!)(实际上是变量子集的中位数)。通常我可以轻松地从数据库中读取数据,explode() 逗号分隔的数据并将中位数相关数据存储到数组 [var] [row] 中。比我可以排序()数组,我得到了中位数。
但是,有一个域没有 100 或 1000 条数据记录(行),而是 80K。给定 20 个中值相关变量,这是 160 万个整数值(32 位)或 51 MB 原始整数数据(可能是两倍,因为我正在使用 64 位 Linux 机器)。到目前为止,一切都很好——但是数组结构有一些开销,所以它变得比 128 MB 大得多。这是我的 PHP 内存不足的地方。
我不想做的事
当然,我可以增加每个 PHP 脚本的内存限制。由于各种原因,我想避免这种情况。
还有一些算法不需要存储 n 值来计算中位数,但会对 n/2 (+x) 感到满意,但将内存负载降低到 50%+X 可能不足以解决问题。
我还可以计算每个变量的中值变量。但这需要我从数据库中加载 80K 行数据 20 次,并一次又一次地执行explode()。这将大大增加脚本运行时间。
[编辑] 数据库当前未标准化(对每个数据行使用 CSV 数据)。出于性能原因,这是有意和必要的。因此我不喜欢规范化数据库,因为这会导致一个包含 100M 条目和巨大索引的表。
我想做什么
我们说的是不超过 51 MB 的原始 32 位整数值。是否有任何改变可以将开销减少到百分之几?甚至可能在 64 位机器上?
我知道自 PHP 5.0.0 以来可用的 SPL 扩展,但我还没有找到如何使用此扩展节省内存的解决方案。谁能给我一个提示——通过 SPL 或使用其他解决方案(默认情况下最好在 PHP 中提供)?
示例代码
private function retrieveReferences() {
$query = $this->getResultsQuery(true);
$times = array();
$tp = -1; // Length of $times - 1
while ($row = $query->fetchArray()) {
$timeSrc = explode(',', $row['times']);
// Store the times per page
foreach ($timeSrc as $p=>$s) {
// Should be faster than checking isset $times[$p] all the time
while ($p > $tp) {
$times[] = array();
$tp = count($times) - 1;
}
$times[$p][] = (int)$s;
}
}
// Compute median for each $times[$p]
// <snip>
}