如何绕过PHP内存限制

时间:2017-06-19 20:32:46

标签: php mysql memory

所以,我们有一个有趣的场景。我们的客户有一个我们构建它们的自定义CMS。其中一个部分允许批处理记录,因此它显示为表格。每条记录都有一些文本字段和一个选择框。当数据库很小时,这很好用,但现在表中有超过10,000条记录,并且生成这些选择框正在扼杀我们的PHP内存限制。

我不是在找人为我编写代码,而是想让我了解更好的方法。

以下是它的工作原理:

1)进行数据库调用,生成用于填充选择框的选项列表。它作为一个名为$topping_images的巨大连接字符串变量从PHP返回到前端,如下所示:

<option>Select an image</option><option value="cheese_mozz_ML.png">cheese_mozz_ML.png</option><option value="cheese_mozz_ML_HT.png">cheese_mozz_ML_HT.png</option><option value="cheese_mozz_ML_pan.png">cheese_mozz_ML_pan.png</option><option value="cheese_mozz_ML_SC.png">cheese_mozz_ML_SC.png</option>

2)进行数据库调用,返回要显示的记录;作为一个名为$toppings的数组返回。

3)像这样生成我们的表:

<? 
$x = 0;
foreach ($toppings as $topping) : ?>
    <tr>
        <td style="width:25%">
            <input type="text" id="t_name<?= $x ?>" value="<?= $topping['topping_name'] ?>" />
        </td>

        <td style="width:29%">
            <input type="hidden" id="topp_img_hdn<?= $x ?>" value="<?= $topping['image_path']; ?>" />
            <select id="topp_img<?= $x ?>">
                <?= $topping_images ?>
            </select>
        </td>
    <? $x++; ?>
<? endforeach; ?>

我们无法更改内存限制(通过php.ini或使用ini_set('memory_limit')),我们的客户端绝对拒绝考虑分页,以允许将较小的数据集发送到每个页面加载。

我是否错过了一种减少处理时间和内存使用量的明显方法?

3 个答案:

答案 0 :(得分:1)

烨。停止使用fetchAll()。在任何给定时间内,只保留1行,即实际处理的行。

$rows=$db->query("SELECT * FROM tbl")->fetchAll(PDO::FETCH_ASSOC);
foreach($rows as $row){...}
如果有很多行,这可能会占用大量内存,因为它会同时将所有行保留在内存中。

现在,这个几乎相同的代码,

foreach($db->query("SELECT * FROM tbl",PDO::FETCH_ASSOC) as $row){...}

只保留1行,即你正在使用的行,在任何给定时间内存(除了垃圾收集器中的滞后,我猜测在任何给定时间最多2行)

答案 1 :(得分:1)

我建议:

所以,例如:

<? 
$x = 0;
foreach ($toppings as $topping) : ?>
    <tr>
        <td style="width:25%">
            <input type="text" id="t_name<?= $x ?>" value="<?= $topping['topping_name'] ?>" />
        </td>

        <td style="width:29%">
            <input type="hidden" id="topp_img_hdn<?= $x ?>" value="<?= $topping['image_path']; ?>" />
            <select class="topping-images" id="topp_img<?= $x ?>"></select>
        </td>
    </tr>
<? $x++; ?>
<? endforeach; ?>
<script>
    $(".topping-images").select2({
        data: <?= json_encode($topping_images); ?>
    });
</script>

此解决方案的另一个好处是,现在可以搜索这个庞大的列表。

编辑:您可以使用普通的旧jQuery实现类似的效果

我还没有对此进行过测试,它绝对不是最优雅的解决方案,但它看起来应该可行。

<script>
var optionsArr = <?= json_encode($topping_images); ?>;

var options = optionsArr.map(function(topping){
    return '<option value="' + topping.id + '">' + topping.name + '</option>';
}).join('');

$('.topping-images').html(options);
</script>

答案 2 :(得分:0)

不确定你是否还需要一个解决方案,但我今天偶然发现了一种可能性......

问题很可能出在foreach循环中,因为它必须将整个数据集加载到内存中。  Generators允许您迭代内存占用空间更小的数据集,因此可以缓解此问题。