Importando CSV a MySql eficientemente con Laravel PHP

En ocaciones se nos presenta el caso donde tenemos que importar un archivo csv y almacenar los registros en la base de datos, normalmente lo que se hace es leer el archivo e ir insertando uno a uno los registros pero este proceso se vuelve lento y tardado cuando la cantidad de registros a insertar es demasiado grande por ejemplo unos 10,000 items.

El proceso que mostraré fue probado con un archivo de 500,000 registros y con un tiempo de ejecución de ~8s, este tiempo puede variar en dependencia del entorno en donde se este ejecutando el código.

Response Time

Les comparto el gist del archivo utilizado para las pruebas: ver en GitHub

style="display:block; text-align:center;" data-ad-format="fluid" data-ad-layout="in-article" data-ad-client="ca-pub-2384244548418509" data-ad-slot="5598091403">

Creacion de nuestra tabla

Para crear la tabla utilizaremos el proceso de migraciones

php artisan make:migration create_imports_table

public function up()  
    {
        Schema::create('imports', function (Blueprint $table) {
            $table->increments('id');
            $table->string('email');
            $table->string('fname');
            $table->string('lname');
            $table->string('address');
            $table->string('city');
            $table->string('state');
            $table->string('zip');
            $table->string('phone');
            $table->ipAddress('ip');
            $table->string('datetime');
            $table->string('source');
            $table->string('gender')->nullable();
            $table->string('birth')->nullable();
            $table->boolean('deliveryverified')->default(false);
            $table->string('verify_date');
            $table->string('smtpresponse');
            $table->timestamps();
        });
    }

Creación del archivo Job para la importación

Un Job en laravel es un servicio que esta ejecutándose en nuestro servidor y realizando diferentes acciones en este acaso se verifica que se agregue una tarea a realizar y se pasa a realizar en segundo plano, brindándonos el beneficio de que un proceso que puede tardar varios minutos en ejecutarse al usuario se le muestre una respuesta en segundos.

Para empezar a crear nuestro Job generaremos el archivo con código inicial con el comando
php artisan make:job ImportCSV

Una vez creado se procede a programar las instrucciones a realizar, nuestro archivo estara situado en la carpeta app/jobs de nuestro proyecto laravel.

Nuestro código quedaría de la siguiente forma, el secreto esta en la instrucción sql LOAD DATA LOCAL INFILE que nos permite insertar todos los registros de nuestro csv en una sola instrucción sql.

Si necesitamos tratar los datos o realizar mayores acciones podemos crear tablas temporales para insertar los datos o simplemente utilizar IF ELSE como es el caso del ejemplo.

Para mas información de la configuración y ejecución de los QUEUE puedes revisar la documentación oficial en https://laravel.com/docs/5.4/queues para que realicen la configuración que mejor se adapte a lo que necesitan.

Subida del archivo

Procedemos a crear la ruta donde recibiremos el archivo, para este ejemplo decide hacerlo directo en la función callback y no en un controlador.

Route::post('/', function (){  
    /* 
     Invocando al JOB de importación. 
     Se le pasa la ruta del archivo que se almaceno
    */
    dispatch(
        new \App\Jobs\ImportCsv(
            request()->file('file')->path()
        )
    );

    return response()->json([
        "success" => true
    ]);
});

Ustedes pueden realizar diferentes validaciones el cual decidí no colocar ya que no es el propósito del articulo.

Conclusión

Mediante este método el proceso de inserción es ejecutado con mejor eficiencia en tiempo a diferencia de haber realizado el proceso de inserción leyendo el archivo e ir insertando uno a uno que lo mas seguro que para archivos grandes muestre un timeout y no logres realizar la importación con éxito.

*Importante

Para que puedan subir archivos de gran tamaño recuerden que tiene que cambiar la configuracion de su servidor web ya sea Nginx o Apache y modificar los parametros upload_max_filesize y post_max_size del archivo php.ini si utilizan Nginx tambien hay que modificar el valor de la variable client_max_body_size.

Jarbit Lira

Read more posts...

Nicaragua

Subscribe to Jarbit Lira

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!