2011-08-03 46 views
8

estoy teniendo un momento muy problemático intentar importar un archivo CSV grande en mysql en localhostimportar grandes CSV en la base de datos MySQL

la CSV es de unos 55 MB y tiene alrededor de 750.000 filas.

ahora que he recurrido a escribir un script que analiza el csv y vuelca las filas 1 por uno

aquí está el código:

$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 

      mysql_query("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng')") or die(mysql_error()); 
     } 
    } 
    fclose($handle); 
} 

el problema es que esto es tomando una eternidad para ejecutar cualquier solución ... sería genial.

+0

¿Tiene índices sobre la mesa? Si es así, considere insertar índices desactivados y reconstruir una vez que haya terminado. –

+0

'load data infile' de mysql puede manejar la mayoría de los formatos csv directamente: http://dev.mysql.com/doc/refman/5.1/en/load-data.html (busque 'csv'). –

Respuesta

6

Usted está reinventando la rueda. Consulte la herramienta mysqlimport, que viene con MySQL. Es una herramienta eficiente para importar archivos de datos CSV.

mysqlimport es una interfaz de línea de comandos para la instrucción SQL LOAD DATA LOCAL INFILE.

Cualquiera de los dos debería ejecutarse 10-20 veces más rápido que haciendo INSERT fila por fila.

+0

lo he intentado pero está plagado de errores después de error. – scarhand

+2

finalmente lo descubrí usando esta guía: http://vegdave.wordpress.com/2007/05/19/import-a-csv-file-to-mysql-via-phpmyadmin/ – scarhand

+0

Gracias a la herramienta CLI 'mysqlimport' ¡trabajó para mi! –

2

Es probable que su problema sea que haya activado el compromiso automático (de manera predeterminada), por lo que MySQL está confirmando una nueva transacción para cada inserción. Debe desactivar la confirmación automática con SET autocommit=0;. Si puede cambiar a usar la biblioteca mysqli (y debe hacerlo si es posible), puede usar mysqli::autocommit(false) para desactivar el autocommitting.

$mysqli = new mysqli('localhost','db_user','my_password','mysql'); 
$mysqli->autocommit(false); 
$stmt=$mysqli->prepare("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
        values (?, ?, ?, ?, ?, ?, ?, ?);") 


$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 
      $stmt->bind_param('ssssssdd', $arr[1], $arr[2], toAscii(arr[2]), $arr[3], toAscii($arr[3]), $arr[4], $arr[6], $arr[7]); 
      $stmt->execute(); 
     } 
    } 
} 
$mysqli->commit(); 
fclose($handle); 
1

intente hacerlo en una consulta.

Podría ser limitado por su my.cnf (Configuración de MySQL), aunque

<?php 

$row = 1; 
$query = ("insert into cities "); 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 
      $query .= "(`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng'),"; 

     } 
    } 
    fclose($handle); 
} 
mysql_query(rtrim($query, ",")); 

si no funciona, puede intentar esto (desactivar automático de cometer)

mysql_query("SET autocommit = 0"); 
$row = 1; 
if (($handle = fopen("postal_codes.csv", "r")) !== FALSE) 
{ 
    while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
    { 
     $num = count($data); 
     $row++; 
     for ($c=0; $c < $num; $c++) 
     { 
      $arr = explode('|', $data[$c]); 

      $postcode = mysql_real_escape_string($arr[1]); 
      $city_name = mysql_real_escape_string($arr[2]); 
      $city_slug = mysql_real_escape_string(toAscii($city_name)); 
      $prov_name = mysql_real_escape_string($arr[3]); 
      $prov_slug = mysql_real_escape_string(toAscii($prov_name)); 
      $prov_abbr = mysql_real_escape_string($arr[4]); 
      $lat = mysql_real_escape_string($arr[6]); 
      $lng = mysql_real_escape_string($arr[7]); 

      mysql_query("insert into cities (`postcode`, `city_name`, `city_slug`, `prov_name`, `prov_slug`, `prov_abbr`, `lat`, `lng`) 
         values ('$postcode', '$city_name', '$city_slug', '$prov_name', '$prov_slug', '$prov_abbr', '$lat', '$lng')") or die(mysql_error()); 
     } 
    } 
    fclose($handle); 
} 
+0

insertando a través de una consulta lanzó "Advertencia: Error al enviar el paquete QUERY. PID = 1260" – scarhand

+0

@scarhand: Dije que podría arrojar un error en una consulta ... – genesis

1

lo hice esto con el servidor SQL:

  • Utilicé el comando SQL Bulkinsert combinado con las tablas de datos.
  • Las tablas de datos residen en la memoria y se crean a partir de la lectura de filas dentro del archivo.
  • Cada tabla de datos se crea a partir de un fragmento de filas, no del archivo completo.
  • Realice un seguimiento del trozo procesado manteniendo los punteros de la última fila leída y el tamaño máximo de la porción.
  • Cuando está leyendo el archivo. salga del bucle cuando el ID de la fila> última fila + tamaño del fragmento.
  • Mantener en bucle y seguir insertando.
2

Será mucho más rápido utilizar LOAD DATA si se puede

0

También a veces, cuando está utilizando Cargar datos si hay advertencias, la importación se detendrá. Puede usar la palabra clave ignorar.

LOAD DATA INFILE 'file Path' IGNORE INTO TABLE YOUR_Table 
0

Tuve una situación similar donde NO era posible utilizar LOAD DATA. Las transacciones a veces también eran inaceptables, ya que los datos debían verificarse en busca de duplicados.Sin embargo, la siguiente mejora drásticamente el tiempo de proceso para algunos de mis archivos de datos de importación.

Antes de que el bucle while (CSV Líneas) establece el compromiso automático a 0 y se inicia una transacción (InnoDB solamente):

mysql_query('SET autocommit=0;'); 
mysql_query('START TRANSACTION;'); 

Después de su bucle, cometió y restablecer la confirmación automática de nuevo a 1 (por defecto):

mysql_query('COMMIT;'); 
mysql_query('SET autocommit=1;'); 

Reemplace mysql_query() con cualquier objeto de base de datos que esté usando su código. Espero que esto ayude a otros.

Cuestiones relacionadas