【问题标题】:Large SQL result set taking too much memory - CodeIgniter大型 SQL 结果集占用过多内存 - CodeIgniter
【发布时间】:2012-02-07 08:54:49
【问题描述】:

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

似乎我试图使用超过 128MB 来从 MySQL 服务器检索结果。我正在使用 $query->result_array() 来检索结果。在我得到的结果中,空间方面显然存在严重的开销。假设我检索了 100,000 行,其中包含 3 个整数。所以 100,000*((3*4 + 10)= 2.1MB。(10 是用于列 id 等的字节数)。

我是不是做错了什么?

----------已解决-----------

通过修改CodeIgniter代码解决:link

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

【问题讨论】:

  • 检索块,进程;检索下一个块 ...
  • 听从 Dagon 的建议,不要一次拿走所有数据。
  • @Dagon 你能给我们展示一些关于如何“检索块,处理;检索下一个块”的例子吗?
  • 您的解决方案链接已失效。请说明您是如何解决此问题的

标签: php mysql sql codeigniter


【解决方案1】:

我不确定 CI 究竟如何返回结果,但您绝对不希望将整个数据集放在一个数组中。为什么不根据需要循环遍历每一行?

<?php

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

【讨论】:

  • 根据我的经验,这会导致 CodeIgniter 2.x 将完整的结果集加载到内存中。
  • 我认为@Nate 是对的。 $result 将包含查询的所有结果
【解决方案2】:

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

MySQL's SELECT statement has this option:

[LIMIT {[offset,] row_count | row_count OFFSET offset}]

例如

Limit 10, 200

提供 200 条记录,从记录 10 开始

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 这就是操作码和其他缓存的用途。对于具有合理复杂性的应用程序来说,3MB 不算什么。现在 RAM 相对便宜。如果您获得了数千个页面点击量(在 3MB 存在问题的时间范围内),希望您通过您的用户群获利并为此付费...
      【解决方案5】:

      我在 CI 上遇到了同样的问题。不幸的是,修改数据库后端不是我的选择。所以我的解决方案是在模型中使用mysqli_ 函数并自行循环遍历每条记录:

      $result = mysqli_query($sql);
      while ($row = mysqli_fetch_assoc($result)){
          // process batch
      }
      

      以这种方式处理记录,我不必执行 sql 分页,也不必将所有信息存储在 1 个数组中。这也适用于mysql_ 函数(取决于您使用的数据库驱动程序)。这里的缺点:

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

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

      【讨论】:

        猜你喜欢
        • 2023-04-05
        • 1970-01-01
        • 2011-03-11
        • 2013-08-02
        • 1970-01-01
        • 2019-08-30
        • 1970-01-01
        • 2016-11-29
        • 1970-01-01
        相关资源
        最近更新 更多