Importation fichier 8G en moins de 1h

Fermé
momo - 31 août 2020 à 11:08
Reivax962 Messages postés 3672 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 - 31 août 2020 à 17:12
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 23329 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 17 novembre 2024 Ambassadeur 1 551
31 août 2020 à 11:21
bonjour, tu ne nous explique pas dans quoi se fait cette importation.
as-tu envisagé d'utiliser
LOAD DATA INFILE
?
0
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 23329 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 17 novembre 2024 1 551
31 août 2020 à 11:54
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 3672 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011
31 août 2020 à 11:44
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
Comment stocker les données et envoyer le tout en un coup sur le $MANAGER->Add?
0
Reivax962 Messages postés 3672 Date d'inscription jeudi 16 juin 2005 Statut Membre Dernière intervention 11 février 2021 1 011 > momo
Modifié le 31 août 2020 à 17:14
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
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