Menú Principal

CSV-PHP-MySQL

Iniciado por caishi, 12 Junio 2016, 23:33 PM

0 Miembros y 2 Visitantes están viendo este tema.

caishi

Hola.
cuento rápidamente, tengo que cargar un fichero CSV a mi base de datos (mysql), comparar existencia, y aplicar update si corresponde.

bien, esa es la parte facil

Problema:
1)mas de 5000 registros termina saturando el servidor y puff... inserta los registros hasta que cae.
2)tengo que traer el archivo en utf-8, el programa que exporta el archivo me lo da en ascci

Solucion tratada:
1) dividir el archivo en 5000 registros cad uno
2) guardar con notepad en utf-8

Requiero:
1)poder cargar los 10000 o 100000 registros de un unico archivo sin dividirlo.
2)convertir archivo cuando se hace el upload a utf-8

Me gustaría:
1)mostrar barra de progreso de upload+proceso del csv a la db (se que se requiere ajax)

Bien, he intentado de todo pero se ve que mis conocimientos no son suficientes.

dejo fragmento de mi código, el cual no tiene mucha ciencia, pero mas o menos para que se entienda..

Si alguno conoce algún ejemplo por ahi que pueda adaptar a mi codigo, les estaria muy agradecido.


<form enctype="multipart/form-data" action="<?php $_SERVER['PHP_SELF'?>"method="post">
  <label>Seleccione el archivo formato CSV:</label>
  <input size="50" type="file" name="filename2"/>
  <input type="submit" name="cargararchivo2" value="Cargar"/>
</form>

<?php
if (isset($_POST['cargararchivo2'])) 
{
  if (
is_uploaded_file($_FILES['filename2']['tmp_name'])){}
  
$handle fopen($_FILES['filename2']['tmp_name'], "r");
  while ((
$data fgetcsv($handle1000";")) !== FALSE
  {
    
$query sprintf("SELECT carton,numerocert FROM regcertificados WHERE regcertificados.carton = '%s' AND regcertificados.numerocert = '%s'" $data[6],$data[9]);
    
$result=mysql_query($query,$link);
    if (
mysql_num_rows($result)) 
    {
      if (
$data[14]!="")
      {
         
$fecha=date ("Y-m-d H:i:s");
         
$data[14] = addslashes ($data[51]);
         
$actualiza="UPDATE regcertificados SET prorroga='$data[14]',actualizado='$fecha' WHERE carton = '$data[6]' AND numerocert='$data[9]'";
         
mysql_query($actualiza,$link) or die(mysql_error());
      }
    }else 
   {
$fecha=date ("Y-m-d H:i:s");
$data[1] = addslashes ($data[1]);
$data[2] = addslashes ($data[2]);
                        
$data....
                        ......
//el resto


$import="INSERT into regcertificados(dni,nombre......) values('$data[0]','$data[1]','$data......')";
mysql_query($import,$link) or die(mysql_error());
   }
  }
 
fclose($handle);
 
$borraRenglon="DELETE FROM regcertificados WHERE dni LIKE '%borrar renglon'";
 
mysql_query($borraRenglon,$link) or die(mysql_error());
 echo 
'<div class="alert alert-success">';
echo '<button type="button" class="close" data-dismiss="alert">&times;</button>';
echo '<strong>Hecho</strong> Los datos incluidos en '.$_FILES["filename"].' se importaron correctamente.';
  echo 
'</div>';
}
?>


PD: $borraRenglon es porque y no se por que, la primer linea del CSV se sube a la db con un caracter invisible, asi que le puse el borrar renglon que lleva ese caracter y lo elimino asi,.

OzX

Hola!
Lo que yo haria, seria pre procesar el CSV, dejando un archivo solo con los archivos que voy a insertar. No es necesario que lo hagas con PHP, puede ser en python o en otro lenguaje.

Luego utilizaría PREPARE (MYSQL) para optimizar los insert, delete, update.

No son tantos registros en realidad, puede ser que tengas que aumentar el buffer en PHP, porque insisto no son tantos registros.

Saludos!




caishi

bueno, cmo los administradores dejaron el tema acá, sigo acá- disculpas por no ponerlo en php-

respondiendo a OzX, primer gracias y luego debo decir que el hosting (hostinger) es compartido y no admite otro lenguaje, solo los comunes, php, js, html, etc.

lo de PREPARE nunca lo use, voy a investigar.
supongo que lo que teng que hacer es "preparar" todo, para luego ejecutarlo fuera del while (($data = fgetcsv($...???

OzX

Cita de: caishi en 13 Junio 2016, 02:02 AM
bueno, cmo los administradores dejaron el tema acá, sigo acá- disculpas por no ponerlo en php-

respondiendo a OzX, primer gracias y luego debo decir que el hosting (hostinger) es compartido y no admite otro lenguaje, solo los comunes, php, js, html, etc.

lo de PREPARE nunca lo use, voy a investigar.
supongo que lo que teng que hacer es "preparar" todo, para luego ejecutarlo fuera del while (($data = fgetcsv($...???

Con lo de PREPARE hago relacion a esto
http://www.w3schools.com/php/php_mysql_prepared_statements.asp

Intenta probar tu solucion en tu localhost, si te funciona bien recien pasalo al hosting.

¿Que error te muestra cuando dices que se te cae?



caishi

Hola. Cuando son muchos registros, más de 5000, da error 500 infernal server error. Es totalmente variable cuando cae, pero es entre los 5000 y 10000 registros.
No se si así es como funciona php y MySQL, o si con mysqli se arregla o con el prepare o si me estoy olvidando de algo :(

OzX

Cita de: caishi en 13 Junio 2016, 04:50 AM
Hola. Cuando son muchos registros, más de 5000, da error 500 infernal server error. Es totalmente variable cuando cae, pero es entre los 5000 y 10000 registros.
No se si así es como funciona php y MySQL, o si con mysqli se arregla o con el prepare o si me estoy olvidando de algo :(

Primero que todo, testea tu script de forma local y luego en el servidor.

En el inicio de tu script php, agrega esto.

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);


Cuando nuevamente te tire error, ve si sale algo, si no ve el error.log de apache y revisa que error es, ya que con eso puedes seguir avanzando hacia la solución.

Saludos.





caishi

Gracias. hoy por la tarde estaré probando esto. (soy de Argentina).
Abrazo!

daniela Vega

para lo de la saturacion del servidor, Casi segura que el problema está o en los índices o en la query. Puedes utilizar varias herramientas para monitorizar esto, over la opción EXPLAIN de tu query.
Un millón de registros es poco, no debería causarte problemas

caishi

bueno, me estoy rindiendo jaja

primero pase todo a mysqli...valía para actualizarse..

intenté:

1) sin modificaciones (mas que pasar a mysali), mejoró la cantidad de registros, pero no llega a 20000.

2) usar prepare, guarda la primer linea del csv y luego devuelve "Catchable fatal error: Object of class mysqli could not be converted to string in..." por que la primera si y e resto no.. no se...

ni pienso en el millon de registros cuando no llego a los 100.000 :(

revise el log, y no ha errores.. cuando tira internal server error :(

el php del hosting tiene lo siguiente:

max_execution_time   240
max_file_uploads      20
max_input_nesting_level    64
max_input_time   240
max_input_vars   3000
memory_limit   512M

en mi pc configure todo esto a mucho mas, e igualmente colapsa en cierto punto la consulta...

Pregunto, existirá alguien tan amable que pueda ajustar mi código para que no exista este problema?

(si no moriré separando de a 5000 registros cada vez que tengo que actualizar :()


<form enctype="multipart/form-data" action="<?php $_SERVER['PHP_SELF'?>" method="post"> //
<label>Seleccione el archivo formato CSV:</label>
<input size="50" type="file" name="filename2"/>
<input type="submit" name="cargararchivo2" value="Cargar"/>
</form>
<?php
if (isset($_POST['cargararchivo2'])) 
{
if (is_uploaded_file($_FILES['filename2']['tmp_name'])){}
$handle fopen($_FILES['filename2']['tmp_name'], "r");
while (($data fgetcsv($handle1000";")) !== FALSE
{
$query sprintf("SELECT carton,numerocert FROM regcertifica2 
WHERE regcertifica2.carton = '%s' 
AND regcertifica2.numerocert = '%s'" 
,
$data[6],$data[9]);
$result=mysqli_query($link,$query);
if (mysqli_num_rows($result)) 
{
if ($data[14]!="")
{
$fecha=date ("Y-m-d H:i:s");
$data[14] = addslashes ($data[14]);
$actualiza="UPDATE regcertifica2 
    SET prorroga='
$data[14]',
actualizado='
$fecha
    WHERE carton = '
$data[6]' AND numerocert='$data[9]'";
mysqli_query($link,$actualiza) or die(mysqli_error());
}
}else 
{
$fecha=date ("Y-m-d H:i:s");
$data[1] = addslashes ($data[1]);
$data[2] = addslashes ($data[2]);
$data[3] = addslashes ($data[3]);
$data[4] = addslashes ($data[4]);
$data[5] = addslashes ($data[5]);
$data[6] = addslashes ($data[6]);
$data[7] = addslashes ($data[7]);
$data[8] = addslashes ($data[8]);
$data[9] = addslashes ($data[9]);
$data[10] = addslashes ($data[10]);
$data[11] = addslashes ($data[11]);
$data[12] = addslashes ($data[12]);
$data[13] = addslashes ($data[13]);
$data[14] = addslashes ($data[14]);
$data[15] = addslashes ($data[15]);


$import="INSERT into regcertifica2(dni,nombre,apellido,fechanac,sexo,
   nacionalidad,carton,certificadoes,
   certificadoin,numerocert,reglaes,
   reglain,fechaexp,fechavenc,prorroga,
   estado,actualizado) 
values('
$data[0]','$data[1]','$data[2]','$data[3]','$data[4]',
'
$data[5]','$data[6]','$data[7]','$data[8]','$data[9]','$data[10]',
'
$data[11]','$data[12]','$data[13]','$data[14]','$data[15]','$fecha')";
mysqli_query($link,$import) or die(mysqli_error());
}
}
fclose($handle);
$borraRenglon="DELETE FROM regcertifica2 WHERE dni LIKE '%borrar renglon'";
mysqli_query($link,$borraRenglon) or die(mysqli_error());
echo '<div class="alert alert-success">';
echo '<button type="button" class="close" data-dismiss="alert">&times;</button>';
echo '<strong>Hecho</strong> Los datos incluidos en '.$_FILES["filename"].' se importaron correctamente.';
echo '</div>';
}
?>




caishi

bueno, despues de romperme tanto la cabeza, he "comentado"( -// */) todo lo que ha insert, update, y demas... o sea, quedando solo el leer el csv. Adivinen que, esto es lo que tarda una eternidad, incluso en local....

alguna idea?