【问题标题】:Handling fetchAll from huge mysql query without memoy limit error处理 fetch All 从巨大的 mysql 查询没有内存限制错误
【发布时间】:2017-02-23 08:19:26
【问题描述】:

我正在尝试从一个 mysql 表中获取大量数据以导出为 XLSX 文件。

我使用了 fetchAll() 函数,但我得到了

Fatal error: Out of memory

这是我的代码:

<?php
require_once 'classes/Spout/Autoloader/autoload.php';
use Box\Spout\Writer\WriterFactory;
use Box\Spout\Common\Type;

$query  = "SELECT *
           FROM full_report";

$header = array('DATA','STORE','FROM','TO','DATE','YEAR','MONTH','ITEM','SIZE','DEPT','SUBDEPT','DESC1','DESC2','GENDER','ATTR','VEND','SEASON','INVO#','TRANS#','QTY','MSRP','RTP','COST','T.RTP','T.COST','PAYMENT','STATUS');

$mDb->query($query);
$result = $mDb->fetchAll(); // Here where I get the error!

$fileName = "fullReport-" . date('m-d-Y-H-i-s') . ".xlsx";
$path     = "_uploads/" . $fileName;

$writer = WriterFactory::create(Type::XLSX); // for XLSX files
$writer->openToFile($path); // write data to a file or to a PHP stream
$writer->openToBrowser($path); // stream data directly to the browser
$writer->addRow($header);

foreach ($result as $value)
{
    unset($value['id']);
    unset($value[0]);
    $valuex[] = array_values($value);
}
$writer->addRows($valuex);
$writer->close();

有什么建议吗?

【问题讨论】:

标签: php mysql out-of-memory limit fetchall


【解决方案1】:

我会建议你使用 SELECT * FROM your table name into out file 'folder path / yourlfilename.extension' ;根据您的要求自定义查询。它可以根据您的要求轻松定制。研究一下mysql变成outfile函数。在海量数据的情况下,这是最好的解决方案。确保您的最后一个文件夹具有“777”权限,并且不存在具有该名称的文件。查询会自行生成文件。

【讨论】:

    【解决方案2】:

    fetchAll 是问题所在。它所做的是从表中获取所有匹配的行并将所有内容加载到内存中。它适用于您没有太多要获取的行,但当要存储的行数超过可用内存量时会导致 Out of Memory 错误。

    要解决此问题,您应该以多个块的形式获取数据。您可以改用fetch 方法和游标。它在 PHP.net 手册中有很好的记录。您也可以在此回购:https://github.com/adrilo/spout-pdo-example。它为您提供了一个以可扩展方式一起使用 MySQL 和 Spout 的示例。

    【讨论】:

    • 这行得通,但是有很多查询会使服务器停机,我这样做了,服务也停机了。
    • 如果您发送正确的请求,您的数据库应该能够轻松处理负载。您需要知道的是偏移/限制模式不起作用。相反,您需要使用 last_fetched_id/limit 模式,以便您的数据库可以跳过已经获取的行。如果您查看我提供的链接中的示例,那就是它的工作原理。
    • 是的,我知道这个例子,我已经完成了整个解决方案并且它运行良好,除非我得到大量数据,服务器会由于查询次数而停机。如果您能建议如何优化 mysql 数据库以处理这些查询,我将不胜感激。
    • 我的建议是确保您拥有正确的索引。否则,您将不得不进行全表扫描,这肯定会使您的网站瘫痪。您可以使用 EXPLAIN 关键字(假设您使用 MySQL)来了解 MySQL 如何获取数据以及它是否使用索引。如果您使用索引,请在代码中添加 sleep,以免数据库过载。
    猜你喜欢
    • 1970-01-01
    • 2012-02-01
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 2011-09-20
    • 2010-10-31
    • 2014-06-22
    • 1970-01-01
    相关资源
    最近更新 更多