You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从MySQL读取数据到PHP数组时内存占用过高的原因及优化方案

MySQL数据转PHP数组内存占用过高的原因及优化方案

问题描述

从MySQL表读取14300行数据(表大小10.8MB),通过以下代码存储为多维PHP数组后,内存占用达到约74MB:

$res = mysqli_query( $con, "SELECT * FROM myTable WHERE 1 ORDER BY type ASC, added DESC" );
while( $row = mysqli_fetch_assoc( $res ) ) { 
  $array[$row['cat']][$row['type']][] = $row; 
}

内存检测代码:

echo memory_get_usage(); // 返回74.6MB
echo memory_get_peak_usage(); // 返回74.6MB

注:表中type、cat、added字段均已建立索引

内存占用过高的原因

  1. PHP数组的结构开销:PHP关联数组底层基于哈希表实现,每个键值对都需要额外内存存储哈希表节点、zval容器(包含变量类型、值、引用计数等元数据),这些结构开销远大于原始数据本身的大小。
  2. 多维数组嵌套的额外消耗:你创建的是三维数组,每一层子数组都会生成独立的哈希表结构,进一步累加内存占用。
  3. 关联数组的键名开销:mysqli_fetch_assoc返回的是字符串键名的数组,字符串键本身需要存储字符数据,相比数字索引数组,每个元素的内存消耗更高。
  4. 数据类型转换开销:MySQL返回的原始数据(如整数、日期)会被PHP转换为对应变量类型(通常是字符串或PHP原生类型),转换过程会产生额外内存占用。

优化方案

1. 只查询必要字段

避免使用SELECT *,明确指定业务所需字段,直接减少每行数据的体积:

// 示例:仅查询cat、type及业务核心字段
$res = mysqli_query( $con, "SELECT cat, type, col1, col2 FROM myTable ORDER BY type ASC, added DESC" );

2. 使用索引数组代替关联数组

用mysqli_fetch_row或mysqli_fetch_array(MYSQLI_NUM)获取数字索引数组,省去字符串键名的内存开销:

while( $row = mysqli_fetch_row( $res ) ) { 
  // 注意按查询字段顺序对应cat、type的位置
  $array[$row[0]][$row[1]][] = $row; 
}

3. 减少数组嵌套层级

如果业务逻辑允许,将多维结构改为一维数组,用组合键替代嵌套:

while( $row = mysqli_fetch_assoc( $res ) ) { 
  $key = "{$row['cat']}_{$row['type']}";
  $array[$key][] = $row; 
}

4. 使用生成器分批处理(PHP 5.5+)

如果不需要一次性加载所有数据到内存,用生成器逐个返回数据,彻底降低内存峰值:

function getTableData($con) {
    $res = mysqli_query($con, "SELECT cat, type, col1, col2 FROM myTable ORDER BY type ASC, added DESC");
    while ($row = mysqli_fetch_assoc($res)) {
        yield [$row['cat'], $row['type']] => $row;
    }
}

// 遍历生成器处理数据
foreach (getTableData($con) as $key => $row) {
    // 逐个处理逻辑
}

5. 分批查询数据

如果必须保留完整数组,可通过LIMIT和OFFSET分批读取并合并,避免一次性加载所有数据:

$totalRows = 14300;
$batchSize = 1000;
$array = [];

for ($offset = 0; $offset < $totalRows; $offset += $batchSize) {
    $res = mysqli_query( $con, "SELECT cat, type, col1, col2 FROM myTable ORDER BY type ASC, added DESC LIMIT $offset, $batchSize" );
    while( $row = mysqli_fetch_assoc( $res ) ) { 
        $array[$row['cat']][$row['type']][] = $row; 
    }
}

6. 调整PHP内存配置(治标不治本)

若以上优化仍无法满足需求,可临时修改php.ini中的memory_limit参数,但这仅为缓解手段,不推荐作为优先方案。


内容的提问来源于stack exchange,提问作者ipel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 20:38:14