Importation fichier 8G en moins de 1h

momo -  
Reivax962 Messages postés 3742 Statut Membre -
Bonjour, quelqu'un aurait une portion de code permettant d'importer un fichier csv de 500 Mo en moins de 30 min.
J'utilise le code suivant qui fait une journée pour importer un fichier de 223 Mo.
		if (isset($_FILES["file"]['name'])) {
			$fileName = $_FILES["file"]["tmp_name"];
			$row = 0;
			if ($_FILES["file"]["size"] > 0) {
				$file = fopen($fileName, "r");				
		        while(($column = fgetcsv($file, $_FILES["file"]["size"]+1, ";")) !== FALSE) {
					$row ++ ;
					if($row>1){
						$_PDO->beginTransaction(); 
								try {
									
									$table = new classe_table(NULL,$column[0],$column[1],$column[2],$column[3],$column[4],$column[5],$column[6],$column[7],$column[8],$column[9],$column[10],$column[11],$column[12],$column[13]);						
									$MANAGER->Add($table);
									if($MANAGER->_Reponse->_Etat == _REPONSE_ERROR_){	
										
										$_PDO->rollback();
										
									}else{
										
										// Validation de la transaction
										 $_PDO->commit();
									}
								} catch (PDOException $e) {
									die("Error: " . $e->getMessage());
								}
					}
					
				}
				 fclose($file);				
			}
		}

A voir également:

4 réponses

yg_be Messages postés 24281 Date d'inscription   Statut Contributeur Dernière intervention   Ambassadeur 1 585
 
bonjour, tu ne nous explique pas dans quoi se fait cette importation.
as-tu envisagé d'utiliser
LOAD DATA INFILE
?
0
momo
 
Non je n'utilise pas de LOAD DATA INFILE
La portion de code que j'ai mis tout en haut recois le fichier depuis un formulaire html
et le code js se charge d'envoyer mon fichier à ma page php qui se charge d'inserer dans la base base]de données.

code html

Télécharger : <input type="file" ngf-select="" ng-model="csvpFile" name="file" ngf-accept="'csv/*'" required="">


code js


$scope.upload1 = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.then(function(response) {
}, function(response) {
});
}

$scope.upload = function(){
var file = $scope.csvpFile;
console.log('file is ' );
console.dir(file);
var URI_CONTROLLER_FOLDER = '../Layers/Business/Controller/';
var uploadUrl = URI_CONTROLLER_FOLDER+'fichierController.php?ACTION=_TRAITEMENT_';
$scope.upload1(file, uploadUrl);
}


fichierController.php


if (isset($_FILES["file"]['name'])) {
$fileName = $_FILES["file"]["tmp_name"];
$row = 0;
if ($_FILES["file"]["size"] > 0) {
$file = fopen($fileName, "r");
while(($column = fgetcsv($file, $_FILES["file"]["size"]+1, ";")) !== FALSE) {
$row ++ ;
if($row>1){
$_PDO->beginTransaction();
try {

$table = new classe_table(NULL,$column[0],$column[1],$column[2],$column[3],$column[4],$column[5],$column[6],$column[7],$column[8],$column[9],$column[10],$column[11],$column[12],$column[13]);
$MANAGER->Add($table);
if($MANAGER->_Reponse->_Etat == _REPONSE_ERROR_){

$_PDO->rollback();

}else{

// Validation de la transaction
$_PDO->commit();
}
} catch (PDOException $e) {
die("Error: " . $e->getMessage());
}
}

}
fclose($file);
}
}
0
yg_be Messages postés 24281 Date d'inscription   Statut Contributeur Dernière intervention   1 585
 
de quelle type de base de données s'agit-il?
je suggère d'utiliser
LOAD DATA INFILE
, ou quelque chose de similaire, en fonction du type de base.
0
Reivax962 Messages postés 3742 Statut Membre 1 011
 
Bonjour,

Dans ton code, tu insères les données ligne par ligne en base.
N'as-tu pas le moyen de préparer toutes les données et de ne faire qu'un seul appel à la base de données ? (ou de les gérer par paquets plus gros, par exemple 500 lignes par 500 lignes, à déterminer pour optimiser mémoire utilisée et temps de traitement) ?
Autrement dit, sortir le $MANAGER->Add de la boucle, et n'y garder que le traitement sur $table ?
Comme je ne sais pas ce qu'est exactement ton $MANAGER ni classe_table(), je ne peux pas vraiment être plus précis, mais l'idée c'est de trouver l'équilibre optimal entre nombre d'appel à la base, taille des requête et empreinte mémoire.

Xavier
0
momo
 
Comment stocker les données et envoyer le tout en un coup sur le $MANAGER->Add?
0
Reivax962 Messages postés 3742 Statut Membre 1 011 > momo
 
Avec les fonctions telles qu'elles sont écrites, ça ne va pas être possible. Il faudrait les modifier, ou créer une fonction dédiée.
J'ai trouvé un code qui répond à ton problème (à adapter bien sûr, notamment sur la gestion des erreurs)
Sur la page suivante, regarde la réponse acceptée :
https://stackoverflow.com/questions/15069962/php-pdo-insert-batch-multiple-rows-with-placeholders/15070222#15070222

Par contre n'hésite pas à regarder du côté de ce que te suggère yg_be. Je ne connais pas du tout LOAD DATA INFILE mais vu le nom, ça a l'air dédié à ton usage, ce serait dommage de se priver d'une solution toute faite...
0
momo
 
la classe

class classe_table {
private $champ1 ;
private $champ2 ;
private $champ3 ;
private $champ4 ;
private $champ5 ;

function __construct ($champ1,$champ2,$champ3,$champ4,$champ5) {
$this->champ1 = $champ1 ;
$this->champ2 = $champ2 ;
$this->champ3 = $champ3 ;
$this->champ4 = $champ4 ;
$this->champ5 = $champ5 ;

}
function getchamp1(){ return $this->champ1 ; }
function getchamp2(){ return $this->champ2 ; }
function getchamp3(){ return $this->champ3 ; }
function getchamp4(){ return $this->champ4 ; }
function getchamp5(){ return $this->champ5 ; }


function setchamp1($value) { $this->champ1 = $value ; }
function setchamp2($value) { $this->champ2 = $value ; }
function setchamp3($value) { $this->champ3 = $value ; }
function setchamp4($value) { $this->champ4 = $value ; }
function setchamp5($value) { $this->champ5 = $value ; }

}


code d'insertion

function Add(table $table ){
$retour = FALSE;
$sql="Call table_ADD(:champ1,:champ2,:champ2,:champ3,:champ4,:champ5)";
$parametre=array(":champ1"=> $table->getchamp1(),":champ2"=> $table->getchamp2(),":champ3"=> $table->getchamp3(),":champ4"=> $table->getchamp4(),":champ5"=> $table->getchamp5());
Log::writeLog(_RESSOURCE_FOLDER_,"SQL","SQL-REQUETTE",array(parent::SqlClarifyParametre($sql,$parametre)));
try {
$requette=$this->_PDO->prepare($sql);
$retour=$requette->execute($parametre);
if($retour) {
$this->_Reponse = new Reponse(_REPONSE_SUCCES_ ,array(array($this->_LANGUAGE_["table"]["@INSERT_SUCCES"])),$table) ;
}
else {
$this->_Reponse = new Reponse(_REPONSE_ERROR_ ,array(array($this->_LANGUAGE_["table"]["@INSERT_FAILED"])),$table) ;
}
} catch (PDOException $ex) {
$this->_Reponse = new Reponse(_REPONSE_ERROR_,array(array("PDO",$ex->getMessage())),$table);
}
return $retour;
}
0