所以,我们有一个有趣的场景。我们的客户有一个我们构建它们的自定义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')
),我们的客户端绝对拒绝考虑分页,以允许将较小的数据集发送到每个页面加载。
我是否错过了一种减少处理时间和内存使用量的明显方法?
答案 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)
我建议:
$topping_images
作为数组返回到前端而不是呈现HTML 所以,例如:
<?
$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允许您迭代内存占用空间更小的数据集,因此可以缓解此问题。