【问题标题】:PHP, MySQL - load around 100k records and export them to xmlPHP,MySQL - 加载大约 100k 条记录并将它们导出到 xml
【发布时间】:2016-07-19 10:02:41
【问题描述】:

我有 100 万行的 MySQL InnoDB 表,我选择了 100K 行进行导出。表格大约有 200 列。

到目前为止我做了什么:

  1. 不是用*全选

    SELECT column1, column2, ... FROM my_table WHERE deleted=0 -- 加载 100k 条记录

  2. 使用带有flush的XMLWriter php库

    $writer = new XMLWriter();
    $writer->openMemory();
    $writer->setIndent(true);
    $writer->startDocument('1.0', 'UTF-8');
    $writer->startElement('export');
    
    $iterator = 0;
    $data = $this->getData();
    
    foreach($adverts as $advert) {
        $writer->startElement('ad');
        $writer->writeElement('id', $data->id);
        // .. other columns
    
        $writer->endElement(); // end ad
    
        if (0 == $iterator % 1000) {
            file_put_contents($this->getFilePath(), $writer->flush(TRUE), FILE_APPEND);
        }
    
        $iterator++;
    }
    

但我仍然有致命错误:允许的内存大小为 ... 字节耗尽

还有其他方法可以优化吗?我想我也许可以通过其他方式从数据库加载数据,比如在第一轮只加载 ids,然后选择 IN (10k_ids),但我还没有测试这个想法。

感谢您的意见。


我的问题与How to export HTML table with 100K records with number formatting without memory exhaust中的问题非常相似

但是没有办法实现低内存消耗。

【问题讨论】:

  • 人们还在使用 XML? ;-)
  • 写几个文件,每个10k?
  • 必须是一个文件。我的想法是从数据库中使用 foreach 加载 10k,因此在变量中保存了较小的数据
  • @ManicDepression 效果如何?
  • 我加载了我的问题中的所有数据。现在我用函数 getData() 只加载部分数据。限制设置为 10 000 条记录,所以我没有像以前那样庞大的数据,大约 120 000 条记录。我还需要 ORDER BY 以升序对项目进行排序,所以我可以使用 $id > $lastId from last cycle。

标签: php mysql xml


【解决方案1】:

我找到了解决方案,问题是我加载了很多数据。

我进行了 3 次升级:

  1. 使用函数记录内存限制

    /**
     * @param $message
     */
    protected function logMemoryUsage($message)
    {
        Debugger::log($message . ": " . memory_get_usage()/1048576 ." MB");
    }
    
  2. 然后我使用 fopen + fwrite + fclose 代替 file_put_contents

    $file = fopen($this->getFilePath(), 'a+');
    fwrite($file, $writer->flush(TRUE));
    fclose($file);
    
  3. 循环加载数据(一次仅10k条记录)

    $this->logMemoryUsage("Memory usage before load");
    $data = $this->getData($lastId);
    
    do {
        $this->logMemoryUsage("Memory usage");
        $lastId = NULL;
    
        foreach($data as $item) {
            $writer->startElement('ad');
            $writer->writeElement('id', $item->id);
            ...
    
            if (0 == $iterator % 5000) {
                fwrite($file, $writer->flush(TRUE));
            }
    
            $lastId = $item->id;
            $iterator++;
        }
    
        $data = $this->getData($lastId);
    
    } while(!empty($data));
    
    $this->logMemoryUsage("Memory usage after");
    fwrite($file, $writer->flush(TRUE));
    fclose($file);
    
    
    
    public function getData($fromId = NULL, $limit = 10000)
    {
        $data = db::query("SELECT a,b,c FROM my_table WHERE deleted=0 AND id>? ORDER BY id ASC LIMIT ?", $fromId, $limit)->fetchAll();
    }
    

现在的输出是:

    export start
    Memory usage before load: 3.6202011108398 MB
    Memory usage: 59.487106323242 MB
    Memory usage: 124.53610229492 MB
    Memory usage: 124.89745330811 MB
    Memory usage: 124.43883514404 MB
    Memory usage: 124.20503234863 MB
    Memory usage: 124.2151184082 MB
    Memory usage: 124.46990966797 MB
    Memory usage: 106.50185394287 MB
    Memory usage: 53.009048461914 MB
    export end

【讨论】:

    猜你喜欢
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多