【问题标题】:How to export Mysql (big) table to CSV using laravel?如何使用 laravel 将 Mysql(大)表导出为 CSV?
【发布时间】:2015-08-21 07:52:46
【问题描述】:

您好,我正在尝试导出大表(100 万行到 CSV 文件中) 使用 laravel 5 框架。

粘贴在下面的代码无法正常工作,因为它分配了太多内存。所有结果都存储在内存中,直到我完成写入文件(php exec)

起初我尝试过(非常不高效)

1.从数据库中获取结果

$mytable = 'table';
                $filePath = storage_path().'/csv/test.csv';

                $mins =  Carbon::now()->subMinutes(10000);

                // set the fetch Assoc mode temoporarly
                DB::setFetchMode(PDO::FETCH_ASSOC);

                $results = DB::table("$mytable")->where('ts_activity', '>=', $mins)->get();

                // revert the fetch Class mode 
                DB::setFetchMode(PDO::FETCH_CLASS);

2。将结果写入文件

if(count($results)>0){
                   $headerLine = implode(',',array_keys($results[0]));

                    dump($headerLine);

                    if(!file_put_contents($filePath, $headerLine.PHP_EOL)){
                        throw new Exception("Cannot write FILE: {$filePath}");                    
                    }

                    foreach($results as $row){   
                        foreach($row as $k=>$v){
                            if($row[$k] == '0000-00-00 00:00:00'){$row[$k] = '';}
                            $row[$k] = trim(str_replace(array(',', "\n", "\r"), ' ', $row[$k]));
                        }

                        //ADDs content to file
                        if(!file_put_contents($filePath, implode(',', $row).PHP_EOL, FILE_APPEND)){
                            throw new Exception("Cannot write FILE: {$filePath}");                    
                        }
                    }

                    //check file size created                
                    $fileSize = filesize($filePath);
                    $reportString   = "Created file at: $filePath of ($fileSize)";
                    //report
                    print($reportString);

                    RETURN TRUE;                            
                }

然后我尝试直接使用mysqli,一切都很好,因为每一行都被提取到内存中,然后在每个循环中写入文件。

 //conection: 
                $link = mysqli_connect(env('DB_HOST'),env('DB_USERNAME'),env('DB_PASSWORD'),env('DB_DATABASE')) or die("Error " . mysqli_error($link)); 

                //consultation: 

                $query = "SELECT * FROM $mytable WHERE ts_activity>='$mins';" or die("Error in the consult.." . mysqli_error($link)); 

                //execute the query. 

                $result = mysqli_query($link, $query); 
                $count = 0;
                while($row = $result->fetch_assoc()) { 
                    if($count++==0){
                        $headerLine = implode(',', array_keys($row));                        
                        dump($headerLine);
                        if(!file_put_contents($filePath, $headerLine.PHP_EOL)){
                            throw new Exception("Cannot write FILE: {$filePath}");                    
                        }
                        continue;
                    }

                    foreach($row as $k=>$v){
                        if($row[$k] == '0000-00-00 00:00:00'){$row[$k] = '';}
                        $row[$k] = trim(str_replace(array(',', "\n", "\r"), ' ', $row[$k]));
                    }

                    //ADDs content to file
                    if(!file_put_contents($filePath, implode(',', $row).PHP_EOL, FILE_APPEND)){
                        throw new Exception("Cannot write FILE: {$filePath}");                    
                    }
                }

如何使用 Laravel 5 类 (DB) 获得相同的效率? 谢谢

【问题讨论】:

    标签: mysql performance csv laravel-5 export


    【解决方案1】:

    您可能想试试这个。这很明显会将您的输出流式传输到文件中。如果这不是您想要的,我认为下一个最好的事情是稍后存储作业和处理,然后在完成时通知/发送给用户。希望这会有所帮助。

    public function export($ids = array())
    {
        $headers = array(
            'Content-Type'        => 'text/csv',
            'Cache-Control'       => 'must-revalidate, post-check=0, pre-check=0',
            'Content-Disposition' => 'attachment; filename=test.csv',
            'Expires'             => '0',
            'Pragma'              => 'public',
        );
    
        $response = new StreamedResponse(function() use($ids){
            // Open output stream
            $handle = fopen('php://output', 'w');
    
            // Add CSV headers
            fputcsv($handle, [
                "Id",
                "Name",
            ]);
    
            User::whereIn('id', $ids)           
                ->chunk(500, function($users) use($handle) {
                foreach ($users as $user) {
                    // Add a new row with data
                    fputcsv($handle, [
                        $user->id,
                        $user->name,
                    ]);
                }
            });
    
            // Close the output stream
            fclose($handle);
        }, 200, $headers);
    
        return $response->send();
    }
    

    【讨论】:

    • 块方法是我正在寻找的。谢谢。
    • @Chathushka 我有 10 万条记录,但它报告了 5 万条记录,它显示了最大执行错误。请帮忙
    • @kunal 对不起,这是一年之后,但它必须是你的 php 最大执行时间限制,可以从你的 php 配置(.ini 文件)中增加
    • @Chathushka 但这不是解决方案,也不推荐。您还有其他解决方案吗?
    • @kunal 很明显,写入仅在执行时间的限制内有效 - 那是用于流写入。也许您可以看看将文件写入磁盘并创建一个下载链接并通过电子邮件发送给用户,但这不是即时的。
    猜你喜欢
    • 2016-11-04
    • 1970-01-01
    • 2013-04-08
    • 1970-01-01
    • 2014-05-12
    • 2016-10-15
    • 1970-01-01
    • 2016-03-20
    • 1970-01-01
    相关资源
    最近更新 更多