2015-08-21 2 views
0

Привет, я пытаюсь экспортировать большую таблицу (1Millions row в CSV-файл) usgin laravel 5 framework.Как экспортировать таблицу Mysql (big) в CSV, используя laravel?

С кодом, вставленным ниже, он не работает нормально, так как он выделяет слишком много памяти. Все результаты сохраняются в памяти, пока я не закончил писать файл (PHP EXEC)

Сначала я судимое (ОЧЕНЬ UNEFFICIENT)

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 классов (БД)? спасибо

ответ

3

Возможно, вы захотите попробовать. Это, безусловно, приведет к потоку вывода в файл. Если это не то, что вы хотите, следующая лучшая вещь, на мой взгляд, будет заключаться в том, чтобы сохранить задание и процесс позже, после чего уведомить/отправить пользователю. Надеюсь это поможет.

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(); 
} 
+0

Chunk method был тем, что я искал. Благодарю. – koalaok

Смежные вопросы