¿Cómo importar grandes ficheros a BD en un tiempo razonable?

Estamos acostumbrados a trabajar con sentencias SQL, INSERT, UPDATE, … Sin embargo cuando tenemos grandes volúmenes de datos y queremos importar desde archivo a BD es mejor utilizar otros comandos. Afortunadamente cualquier Motor de Base de Datos pone a nuestra disposición formas de hacerlo y MySQL no iba a ser menos.

Supongamos que tenemos un archivo de 2Gb de datos, en texto plano para importarlo, de esos que cuando haces doble click, antes de oír el segundo click ya te has arrepentido, sabes que no se abrirá y se comerá la RAM. Podríamos leer linea a línea, construir sentencias INSERT y ejecutarlas… Sin embargo, no terminaríamos nunca.

En su lugar en MySQL tenemos a nuestra disposición el comando LOAD DATA INFILE, gracias a el, con apenas unas indicaciones, haremos todo el trabajo en un tiempo infinitamente menor.

Veamos un ejemplo.

Tenemos el archivo terreno.bck con un peso de 1,2Gb y la siguiente estructura:

ID,TIPO,SECTOR,X,Y,Z
1,54,1,331.54,223.45,382.88
2,54,1,332.44,...

Vamos a importarlo en la tabla TERRA:

ID int unsigned not null
TIPO int not null
SECTOR int not null
X float not null
Y float not null
Z float not null

Podemos probar directamente la sentencia MySQL:

LOAD DATA LOCAL INFILE 'terreno.bck' INTO TABLE TERRA 
FIELDS TERMINATED BY ',' 
LINES TERMINATED BY '\n' 
(ID, TIPO, SECTOR, X, Y, Z)

* Importante, si utilizas directamente «LOAD DATA INFILE», al ejecutar suele aparecer el bonito mensaje: «Error Code: 1290. The MySQL server is running with the –secure-file-priv mysql», se soluciona (al 99%) añadiendo LOCAL en la sentencia, justo antes de INFILE.

Los parámetros son:

  • nombre de archivo origen ‘terreno.bck
  • tabla destino TERRA
  • separador de campos, en nuestro caso ‘,
  • separador de registro, fin de linea, ‘\n
  • por último lista de campos, esto último es opcional, y en este caso daría igual incluirlo o no, sin embargo, en aquellos casos que la tabla tenga más campos y estos no vayan a importarse, dejando el valor por defecto, es necesario incluirlos. Yo por claridad en el código prefiero añadirlos.

En Python seria algo así:

path = "terreno.bck"
tblName = "TERRA"
ssql = ("LOAD DATA LOCAL INFILE '%s' INTO TABLE %s " 
    + "FIELDS TERMINATED BY '|' LINES TERMINATED BY '\n' (PAGID, RECETA)" % (path, tblName))
bexec, result = cnn.Exec(ssql, True)

La clase cnn que ves en el fuente para trabajar con MySQL la tienes en MySQL desde Python, trabajando con MySQLdb

 

¿Que ocurre si uno de los campos es tipo cadena y el texto está entre comillas? Lo indicamos añadiendo OPTIONALLY ENCLOSED BY « de este modo:

LOAD DATA LOCAL INFILE 'terreno.bck' 
INTO TABLE TERRA 
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n' 
(ID, TIPO, SECTOR, X, Y, Z)

 

Eso es todo, Saludos!

 

Deja tu comentario