【问题标题】:How to prevent fatal error of memory size exhaustion [duplicate]如何防止内存大小耗尽的致命错误[重复]
【发布时间】:2014-01-25 07:36:03
【问题描述】:

我正在使用 mysql_fetch_object 检索 10K 记录(有 10 个数据类型为 datetimetextintvarchar 的列)并从查询中的每个连接表中获取所有列,这给出了内存大小耗尽致命错误,但后来我修改了查询以仅获取一些消除错误的特定列,使我免于淹没在错误的湖中。

查询只是将 3 个表 A、B、C 连接为 SELECT * FROM A JOIN B ON ......JOIN C ON ...... WHERE.....

但我仍然担心如果没有。记录或没有。列增加,然后错误会再次出现....那么完整的解决方案是什么?我在 SO 上阅读了其他帖子,发现应该使用 mysql_unbuffered_query。但是如果我使用mysql_fetch_object,就没有解决方案吗?无缓冲查询是否会因为一次返回一行而花费更多时间?

【问题讨论】:

  • 你能给我们实际代码吗?如果你想优化它,我们需要一些东西来优化。顺便说一句,这在 codereview.stackexchange.com 上可能会更好。
  • 显示实际查询。您很可能会生成笛卡尔连接,因此您的 10k 条记录会膨胀成数十亿或数万亿行。
  • 不,我在 mysql 中执行了查询,它实际上返回了 10000 行
  • 您的表中是否有任何 LONGBLOB 或 LONGTEXT 列? PHP 将尝试预先分配足够的内存来保存这些列中可能的最大字符串,而不是实际数据的长度。这意味着它可能会尝试分配 4GB 缓冲区,远远超过 PHP 的默认内存限制。解决方案:改用 MEDIUMBLOB/MEDIUMTEXT。
  • @BillKarwin:我正在使用 TEXT 数据类型,用户可以为该字段输入任何长度的输入,因此我无法限制该字段的大小

标签: php mysql memory-management


【解决方案1】:

这里不是 MySQL 内存不足,而是您的 PHP 脚本,因此减小 SELECT 的大小只是部分解决方案。

我的猜测是你正在做类似的事情:

$collect = array();
while (has_records) {
    $collect[] = fetch_record;
}
foreach ($collect as $row) {
    handle_record($row);
}

当然$collect 会变得很大。看看是否可以避免收集所有记录:读取记录、处理记录、清理内存并进行下一次迭代。

while (has_records) {
    var $row = fetch_record();
    handle_record($row);
}

迭代器示例代码:

class DB {
    function get_iterator($query) {
        $query_result = do_query($query);
        return new Iterator($query_result);
    }
}

class MyIterator {
    public function __construct($mysql_result) {
        $this->res = $mysql_result;
    }
    public function hasMore() {
        // do some counting
    }
    public function fetch() {
        return mysql_fetch($this->res);
    }
}

echo '<table>';
$it = $db->get_iterator("SELECT * FROM `items`");
while($it->hasMore()) {
    echo '<tr>';
    $row = $it->fetch();
    foreach ($row as $cell) {
        echo '<td>' . $cell . '</td>';
    }
    echo '</tr>';
}
echo '</table>';

您甚至可以implements Iterator,这样您就可以直接通过$it foreach,这太棒了。

【讨论】:

  • 是的,你完全正确,我使用的是你发布的方法
  • 好的,这是否有助于您找到解决方案?
  • 这其实是个好主意。您还可以拆分查询以分批进行,例如每批 1k。
  • 是的,你可以,只是你的思维方式不对。而不是$db-&gt;getMeData("rawr") 它为您提供数据(在数组中),您可以让它返回一个迭代器。我添加了一些示例代码。
  • 如果你不熟悉类,这个解决方案可能有点太高级了。去读这个:) php.net/manual/en/language.oop5.basic.php
猜你喜欢
  • 2017-12-13
  • 2013-10-21
  • 2015-07-02
  • 2015-05-30
  • 2020-08-21
  • 2015-11-25
  • 2014-04-04
  • 2011-07-12
  • 1970-01-01
相关资源
最近更新 更多