La comparaison de deux gros fichiers prend plus de quatre heures

J’ai une boutique en ligne qui compte environ 15 000 produits mis à jour quotidiennement. Actuellement, je télécharge la nouvelle liste tous les jours, mais cela pose certains problèmes (comme le temps d’arrêt étant un problème majeur) et je voulais proposer une alternative. J’ai créé un script qui déplace la liste des produits “hier” et télécharge la liste des produits d’aujourd’hui. Ensuite, je passe ligne par ligne et compare les deux fichiers en voyant ce qui doit être supprimé, modifié, créé. Cela me permettra d’effectuer une mise à jour avec un minimum de travail, pas de temps d’arrêt car tout se passera en coulisse via le travail CRON, et c’est comme ça que ça doit être fait.

Le problème est que cela prend plus de quatre heures pour que le processus se déroule et je ne sais pas si ce que je fais est le moyen le plus efficace. Ma première pensée est d’écrire quelque chose en C ++, mais je ne suis pas sûr de savoir combien de temps cela serait comparé à PHP.

Ma question est:

• Est-ce le moyen le plus efficace de le faire?

• PHP est-il le meilleur langage pour faire cela?

Voici mon script que j’ai écrit pour gérer le téléchargement et la comparaison:

public function __construct($url, $user, $pass) { $this->logger = new KLogger("/opt/lampp/htdocs/lea/logs/master.log" , KLogger::INFO); /* increase execution time and server memory limit */ ini_set('max_execution_time', 14400); ini_set('memory_limit', '-1'); /* set veriables */ $this->ftp = ftp_connect($url); $this->login = ftp_login($this->ftp, $user, $pass); $this->old = file('/opt/lampp/htdocs/lea/products/new/temp/rsr_inventory.txt'); $this->new = file('/opt/lampp/htdocs/lea/products/new/rsr_inventory.txt'); $this->list = array(); $this->start_time = date('Hi'); $this->counter = 0; } public function download($to, $from) { // move current file to new location to get new file ready $this->logger->LogInfo('move yesterday\'s products list'); rename('/opt/lampp/htdocs/lea/products/new/temp/rsr_inventory.txt', '/opt/lampp/htdocs/lea/products/new/rsr_inventory.txt'); // get list from rsr $this->logger->LogInfo('get new list from rsr'); if(ftp_get($this->ftp, $to, $from, FTP_BINARY)) { return true; } return false; } public function update() { // initialize process $this->logger->LogInfo('update process initialized'); for($i = 0; $i new); $i++) { $new[$i] = explode(';', $this->new[$i]); $response = $this->_match($new[$i]); if($response[0]) { if(sortingm($response[2]) != sortingm($new[$i][5]) || sortingm($response[3]) != sortingm($new[$i][8])) { $this->list[$this->counter][0] = $response[1]; $this->list[$this->counter][1] = 'update'; $this->list[$this->counter][2] = sortingm($response[2]); $this->list[$this->counter][3] = sortingm($response[3]); $this->counter++; } } else { $this->list[$this->counter][0] = $response[1]; $this->list[$this->counter][1] = 'create'; $this->list[$this->counter][2] = sortingm($response[2]); $this->list[$this->counter][3] = sortingm($response[3]); $this->counter++; } } if(count($this->list) > 0) { //csv $this->logger->LogInfo('create update.csv'); $updates = fopen('/opt/lampp/htdocs/lea/products/new/updates.csv', 'w'); foreach($this->list as $fields) { fputcsv($updates, $fields); } fclose($updates); } $this->logger->LogInfo('product update process complete'); $this->__mail(); } private function _match($item) { for($j = 0; $j old); $j++) { $old[$j] = explode(';', $this->old[$j]); if($item[0] === $old[$j][0]) { return array(true, $item[0], $old[$j][5], $old[$j][8]); } } return array(false, NULL, NULL, NULL); } 

Voici un exemple du fichier products.txt que je reçois chaque jour (je ne montre que 10 produits, mais il y en a environ 15 000 (il manque beaucoup de choses: prix, quantité, etc …, mais j’ai tout réduit up puisque peu importe de les montrer):

 511-10010-019-L-XL;844802282208;5.11 RECON ANKLE SOCK BLK L/XL; 511-10010-036-L-XL;844802282246;5.11 RECON ANKLE SOCK SHADOW L/XL; 511-10010-132-LXL;844802334662;5.11 RECON ANKLE SOCK TIMBER L/XL; 511-10010-200-L-XL;844802282222;5.11 RECON ANKLE SOCK FATIGUE L/XL; 511-10011-019-L-XL;844802276382;5.11 COLD WEATHER OTC SOCK BLK L/XL; 511-10012-019-L-XL;844802276429;5.11 COLD WEATHER CREW SOCK BLK L/XL; 511-30012-019-M;844802269650;5.11 WOMENS HOLSTER SHIRT BLK M; 511-40011-010-L;844802016148;5.11 HOLSTER SHIRT L WHITE; 511-40011-010-M;844802016131;5.11 HOLSTER SHIRT M WHITE; 511-40011-010-XL;844802016155;5.11 HOLSTER SHIRT XL WHITE; 511-40011-010-XXL;844802016162;5.11 HOLSTER SHIRT 2XL WHITE; 

Je pense que votre problème est que vous faites des comparaisons 15 000 x 15 000 (donc 225 millions d’opérations sur les données).

Si vous créez à la place une carte (autrement dit un tableau en PHP) avec un identifiant unique comme index pour l’ancien et le nouveau. C’est-à-dire 30k opérations, puis parcourez la liste en vérifiant si l’autre contient la même chose ou non. C’est une autre opération de 15K. Total de 45 000 opérations, au lieu de 225 millions d’opérations.

Je ne dis pas que la suggestion de faire une firebase database est une mauvaise idée, mais le temps excessif pris est clairement causé par un mauvais choix d’algorithme + une structure de données.

Ceci est un travail pour MySQL. L’importation de vos données constituera un investissement important dès le départ, mais en vaudra la peine à long terme. Les bases de données sont conçues pour mettre à jour, fusionner, supprimer et insérer des données efficacement. Ce type de travail prendrait quelques secondes dans MySQL. Vous pouvez garder PHP comme langage de script.