Optimizar Cactivedataprovider Para Generar Csv Con Miles De Registros

Estoy creando un método para generar un archivo CSV que exporte más de 60 mil registros.

Anteriormente usaba EexcelBehavior y EexcelView pero la memoria del servidor se agotaba con miles de registros y cada vez que la aumentaba pedia más.

Para obtener los datos uso un CActiveDataProvider y es la parte donde tarda muchísimo les dejo mi código:




function ToCsv($model,$dataProvider, $columns){

$totalItemCount=$dataProvider->totalItemCount; // cantidad total de registros 

$chunk= 1000; // cantidad de registros a obtener en el criteria

$fp = fopen( "/tmp/$fileName-".time() .'.csv', 'w+' ); //creo un archivo en tmp

fputs($fp,$this->HeaderCsv($columns) ); // agregó las columnas al archivo


for ( $i=0; $i < $totalItemCount; $i=$i+$chunk )

{

    $dataProvider = new CActiveDataProvider($model,

	array('criteria'=>$this->CriteriaLimit($criteria,$i,$chunk) ) // creo un nuevo dataprovider con un criteria limitado

    );

    $dataProvider->pagination = false; //deshabilito la paginación

    $getData = $dataProvider->getData(); // aquí tarda muchisimo en obtener los datos

    foreach ($getData as $data) {

       foreach ($columns as $column) { // voy recorriendo cada columna del grid (personalizado)

          $value .= !empty($column['value'])? 

		$data->evaluateExpression($column['value'], array('data'=>$data))."\t": //obtengo el valor de la relación del "value" de columns

		$data[$column['name']]."\t";

         }

       $value =substr($value, 0,-1);

       $value .=$newLine;

    }

    fputs($fp, $value);

    

} 

rewind($fp);

$output = stream_get_contents($fp);

fclose($fp);

OutPutCsv($fileName,$output); // mando a descargar el archivo en el navegador

}



¿De que forma puedo optimizar mi metodo para que este soporte miles de registros y no agote la memoria del servidor?

Puedes usar un CDbCommand, ya que no necesitas paginación ni demás funciones que te relentizan.




$data = Yii::app()->db->createCommand()

    ->select('*') // ->select(implode(', ', $columns))

    ->from('tbl_table') // ->from($table)

    ->where('id=:id', array(':id'=>1))

    ->queryAll();



También puedes, si tu servidor te lo permite, modificar algunas limitaciones de PHP, como:

  • max_execution_time

  • memory_limit

  • ignore_user_abort

Estos parámetros se pueden modificar directamente en la configuración de PHP, lo cual no es recomendable, ya que afectaría a todo el servidor, mediante directivas Apache, que puedes limitar a un fichero o directorio, o bien en el mismo script php:




// 0 es sin límite de tiempo, pero puedes poner 9000 por ejemplo

set_time_limit(0); // o ini_set('max_execution_time',0);

ini_set('memory_limit','1500M');

ignore_user_abort(true);



Hola sirpyerre, muy buena función.

Prueba con las opciones que te da Gonzalo M., subiendo la memoria podrás exportar algún registro más, pero seguirás teniendo un límite similar.

Yo creo que con modelos no vas a poder, al menos con yii 1.1.x, más o menos usa tu función para exportaciones pequeñas, medias y para las grandes lo que comenta Gonzalo M.

Se supone que en Yii 2.0 se podrán exportar muchos más registros ya que en lugar de traer lo modelos completos, se puede traer un array de los campos solicitados. Y esto ahorra mucha memoria porque un modelo lleva consigo muchos datos.

Un saludo, de todas maneras si consigues mejorar la función compártela ::)