Php 大型SQL结果集占用太多内存-CodeIgniter

Php 大型SQL结果集占用太多内存-CodeIgniter,php,mysql,sql,codeigniter,Php,Mysql,Sql,Codeigniter,我正在使用CodeIgniter发出一个SQL查询,它可以返回多达80000行作为结果。每行有三列,都是整数,我得到一个PHP错误: 致命错误:允许的内存大小134217728字节已用尽 似乎我正在尝试使用超过128MB的内存从MySQL服务器检索结果。我正在使用$query->result\u array()检索结果。很明显,我得到的结果在空间方面有很大的开销。假设我检索100000行,包含3个整数。因此100000*((3*4+10)=2.1MB。(10是用于列id等的字节数) 我做错什么了

我正在使用CodeIgniter发出一个SQL查询,它可以返回多达80000行作为结果。每行有三列,都是整数,我得到一个PHP错误: 致命错误:允许的内存大小134217728字节已用尽

似乎我正在尝试使用超过128MB的内存从MySQL服务器检索结果。我正在使用$query->result\u array()检索结果。很明显,我得到的结果在空间方面有很大的开销。假设我检索100000行,包含3个整数。因此100000*((3*4+10)=2.1MB。(10是用于列id等的字节数)

我做错什么了吗

----------------------解决-----------------------

通过修改CodeIgniter代码解决:


现在执行速度更快了,脚本只占用了约3MB的内存,而不是128MB以上的内存。

我不确定CI是如何返回结果的,但您肯定不希望将整个数据集放在一个数组中。为什么不根据需要循环每一行呢

<?php

$result = $this->db->query('SELECT ...');
while($row = $result->next_row())
{
  // do something with that single row
}

我不确定CI是如何返回结果的,但您肯定不希望将整个数据集放在一个数组中。为什么不根据需要遍历每一行呢

<?php

$result = $this->db->query('SELECT ...');
while($row = $result->next_row())
{
  // do something with that single row
}

除非您确实需要检索所有记录(例如用于导出或批处理),否则我强烈建议始终查询块

:

比如说

Limit 10, 200

提供以记录10开头的200条记录

除非您确实需要检索所有记录-例如,出于导出或批处理目的-我强烈建议始终查询块

:

比如说

Limit 10, 200

提供以记录10开头的200条记录

即使问题得到了回答,3MB仍然很多。您真的需要将其全部存储在内存中吗?一个普通的PHP内存占用大约1MB或更少,因为它是在考虑内存的情况下编程的。您甚至可能超过8MB这一事实非常令人不安,而且在重新编程时在一个有数千次页面点击的生产环境中,您的服务器将崩溃并烧掉。我强烈建议您修改代码。

即使问题得到了回答,3MB仍然很多。您真的需要将其全部存储在内存中吗?正常的PHP内存占用大约1MB或更少,因为它是在内存的情况下编程的。事实是您甚至可能会超过8MB,这是非常令人不安的,在一个具有数千次页面点击的实际生产环境中,您的服务器将崩溃并烧坏。我强烈建议您修改代码。

如果您要在页面上显示结果,您很可能需要使用分页。如果您正在对数据执行操作,则需要使用限制和偏移量进行分页。否则,您需要增加内存限制,我不建议内存限制大于128MB。

如果要在页面上显示结果,您很可能需要使用分页。如果要对数据执行操作,则需要使用限制和偏移量进行分页。否则,您将需要增加内存限制,我不建议超过128MB。

我遇到了与CI相同的问题。不幸的是,修改DB后端不是我的选择。因此,我的解决方案是在模型中使用
mysqli\uu
函数,并自行循环每个记录:

$result = mysqli_query($sql);
while ($row = mysqli_fetch_assoc($result)){
    // process batch
}
通过这种方式处理记录,我不必进行sql分页,也不必将所有信息存储在1个数组中。这也适用于
mysql\uuu
函数(取决于您使用的DB驱动程序)。缺点如下:

  • 您没有使用CI DB引擎,因此如果您决定使用其他驱动程序,则必须手动更新这些查询
  • 除非您以某种方式存储数据库标识符,否则无法使用多个数据库

可能还有其他缺点,但对我来说,它可以工作并且不消耗那么多数据。

我在CI方面遇到了同样的问题。不幸的是,修改DB后端不是我的选择。因此我的解决方案是在模型中只使用
mysqli\uu
函数,并自行循环每个记录:

$result = mysqli_query($sql);
while ($row = mysqli_fetch_assoc($result)){
    // process batch
}
通过这种方式处理记录,我不必进行sql分页,也不必将所有信息存储在1个数组中。这也适用于
mysql\uuu
函数(取决于您使用的DB驱动程序)。缺点如下:

  • 您没有使用CI DB引擎,因此如果您决定使用其他驱动程序,则必须手动更新这些查询
  • 除非您以某种方式存储数据库标识符,否则无法使用多个数据库

可能还有其他缺点,但对我来说,它可以工作并且不消耗那么多数据。

检索块,处理;检索下一块…按照Dagon的建议,不要一次获取所有数据。@Dagon你能给我们展示一些如何“检索块,处理;检索下一块”的示例吗要在大型查询中完成吗?您的解决方案链接已失效。请解释您是如何解决此问题的检索块、进程;检索下一个块的可能重复项…按照Dagon的建议,不要一次获取所有数据。@Dagon您能否向我们展示一些如何“检索块、进程;检索下一个块”的示例在大型查询中完成?您的解决方案链接已失效。请解释您是如何解决此问题的。这可能是操作码和其他缓存的用途。3MB对于一个具有合理复杂性的应用程序来说已经不算什么了。而且现在RAM相对便宜。如果您获得数千次页面点击(在3MB有问题的时间范围内),希望你能从你的用户群中赚钱来支付…这就是操作码和其他缓存的用途。对于一个合理复杂的应用程序来说,3MB已经不算什么了。而且现在RAM相对便宜。如果你的页面点击量达到数千次(在3MB有问题的时间范围内),希望你能从你的用户群中赚钱来支付…在我的经验中