PHP脚本查询生产环境数据库触发Allowed memory size exhausted报错
故障原因分析
- 最核心的高发原因:第三个部门的
bedrijven表数据量远大于另外两个部门。你的SQL中CONCAT_WS(...) LIKE '%'是无效过滤条件,所有非NULL的拼接结果都符合匹配规则,相当于仅过滤verwijderd=''的记录后就全量返回,没有加LIMIT分页限制。phpmyadmin默认会自动加分页(通常为25/50条/页)仅拉取单页数据,所以不会触发内存问题,但PHP脚本如果默认将全量结果集一次性加载到进程内存,总数据量超过128M(报错中134217728字节对应128M内存上限)就会触发内存耗尽。 - 配置差异原因:该部门站点的PHP内存上限配置低于另外两个部门。检查生产环境三个部门站点的
php.ini、站点目录下的.user.ini、对应Web服务(Nginx/Apache)的站点配置段中的memory_limit参数,确认第三个部门的配置是否和另外两个一致,是否仅设置了128M。 - 数据结构差异原因:该部门表的单行数据体积远大于其他部门。你用了
SELECT *返回所有字段,同时还拼接了多个文本字段生成额外返回值,如果该部门的表中存在大文本字段(比如备注类字段opmerkingen存储了大量内容),单条记录体积会远高于另外两个部门的记录,哪怕总条数相近,全量结果集的总体积也会超出内存上限。 - 数据库扩展配置原因:PHP的结果集获取方式为全量缓冲模式。如果你使用的是
mysqli::store_result或者PDO默认的缓冲查询模式,会把整个结果集全部预加载到PHP进程内存中,就算你写了逐条遍历的逻辑,也会先全量拉取后再遍历。而phpmyadmin默认使用流式查询拉取结果,不会一次性加载全量内容到内存。
修复方案
- 先给SQL末尾加上
LIMIT分页限制,每次仅返回业务需要的固定条数数据,避免一次性拉取全表 - 临时调高该站点的
memory_limit参数,比如调整为256M,验证是否是内存配置不足导致的问题 - 把
SELECT *改为仅返回业务实际需要的字段,去掉无关字段的返回,降低单条记录的体积 - 改用流式查询获取结果集:PDO可以设置属性
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false,mysqli可以调用use_result方法,让结果集逐条从MySQL读取,不会一次性全量加载到PHP内存
内容的提问来源于stack exchange,提问作者user3095854
相关产品推荐
相关产品推荐

