Optimisation d'un code php / requêtes mysql.

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Optimisation d'un code php / requêtes mysql.

Re: Optimisation d'un code php / requêtes mysql.

par J-oxi » 28 mai 2013, 14:33

J'en avais lu un peu a ce sujet, mais ne connais pas du tout ni ne l'utilise.
Pour te donné un aperçu, je doit traiter : 650 fichiers sources (contenant de 100 a 117.000 lignes)
les quels sont trier dans 4 bases, puis 165 tables par base.
Une fois les lignes sources récupéré, j'effectue quelques modifs, avec php puis je les insert dans la base adéquat.
d'ou le fait des deux boucles, qui gère les inserts, et les paramètres de connexion ainsi que les tables dans les quel placé les lignes.
Don je suis pas sur que le load Data soit une bonne solution. je vais (encore) tout refaire, et essayer de feinter un peu pour gagner en temps d'ex.

Re: Optimisation d'un code php / requêtes mysql.

par moogli » 28 mai 2013, 14:24

as tu regardé du coté du load data de mysql ? http://dev.mysql.com/doc/refman/5.0/fr/load-data.html

se serait plus performant si tu vire la couche php ?

@+

Re: Optimisation d'un code php / requêtes mysql.

par J-oxi » 28 mai 2013, 01:02

Oui un time out, mais régler de base a 8h, ça laisse de la marge.. c'est plus à cause du nombre de requêtes (enfin je pense).

Autrement coté exécution, je vais opter pour un insert simple je pense. qui est plus rapide, sans vérification de l’existence, et supprimer les entrés précédentes une fois par jour.
A moins que tu ai d'autres suggestion. A savoir que je devrais avoir un update par jour au minimum :x

Re: Optimisation d'un code php / requêtes mysql.

par moogli » 27 mai 2013, 23:47

c'est assez étonnant comme erreur vue qu'a priori c'est sur un time out :? http://dev.mysql.com/doc/refman/5.0/fr/gone-away.html

par contre effectivement il y a pas mal de donnée et l'insertion semble très lente (test rapid 2000 insertions en une heure on est loin des 5 millions :mrgreen: ).

Chose certaine c'est que peu d'hébergement classique supporterons la charge (ou simplement voudrons la supporter)

vue le volume de donnée je pense que j’essaierai de voir une solution coté serveur.

@+

Re: Optimisation d'un code php / requêtes mysql.

par J-oxi » 27 mai 2013, 14:55

Bonjour,

Alors, j'ai refais mes codes.. sorti les préparation des requêtes, tester les retours...
Sauf qu'après un certain temps mon code renvois : Erreur Insert : MySQL server has gone away.
Il semblerait donc que le nombre de requêtes pose problème.
boucle for -> 50 loop.
boucle foreach -> ~ 100.000 lignes.
Nb de requêtes : 5.000.000 d’exécution..
Certes il gagne en temps d’exécution, mais cesse avant la fin. Galère pour une mise à jour.

Je pensais donc prendre le nombre d’exécution max, le diviser par deux.. Et lancé la boucle foreach en deux fois.. deux pages différentes..
D'autres idées pour éviter ce genre d'erreur?

Re: Optimisation d'un code php / requêtes mysql.

par moogli » 24 mai 2013, 23:18

si c'est un script de dev, tu kill le process :mrgreen:

bon courage


@+

Re: Optimisation d'un code php / requêtes mysql.

par J-oxi » 24 mai 2013, 23:02

Merci pour les conseils, je vais potasser cela demain en journée et refaire un topo au soir.
Je n'ai pas X choix pour la traitement des données, je les sorts d'une Url, pour les traiter voir les modifier pour certain champs, en ajouter.. Sans compter que les sources peuvent changer avec le MaxExe qui peut augmenté.
Puis la vu la boulette que j'ai faite plus tôt... Mon script tourne depuis des heures, je doit attendre que cela finisse.

Re: Optimisation d'un code php / requêtes mysql.

par moogli » 24 mai 2013, 20:15

ben déja tu ne fera ces 3 instructions que 3 fois au lieu de 3 x 100000, du coup tu gagne 300000 - 3 = 299997 fois gagné.
sachant que si tu demande une requete préparé serveur c'est 299997 accès réseau gagné :mrgreen:

ajoute à cela que ton code est pas super correct (par exemple les test pour les messages d'erreur ne peuvent échouer par tu test des objets créer avant et quand une requête, avec le méthode execute de l' objet pdostatement, échoue tu a false en retour.

donc ton code serait un poil plus performant ainsi
<?php
$db = FonctionConnBdd();
$db = new PDO('');
$MaxExe = 50;
// Préparation des requêtes
$TryLine = $db->prepare('SELECT coun(1) as nb FROM Matable WHERE var1=:var1 AND var2=:var2');
$UpdateLine = $db->prepare('UPDATE Matable SET var5=:var5 WHERE var1=:var1 AND var2=:var2');
$InsertLine = $db->prepare('INSERT INTO Matable (var1,var2,var3,var4,var5) VALUES (:var1,:var2,:var3,:var4,:var5)');

for ($i = 0; $i < $MaxExe; $i++) {
    $Source = 'http://urlsource.fr/fichier.txt'; // c'est pas un tableau hein :)
    if (!is_array($Source)) {
        echo 'Erreur Source';
    } else {
        foreach ($Source as $src) {
            list($var1, $var2, $var3, $var4, $var5) = explode(',', $src);
            // Vérification de la présence dans la base

            $ret = $TryLine->execute(array('var1' => $var1, 'var2' => $var2));
            $data = $TryLine->fetchAll();
            $CountLine = $data[0]['nb'];
            $TryLine->closeCursor();
            // Si existant -> update
            if ($CountLine == 1) {
                $ret = $UpdateLine->execute(array('var1' => $var1, 'var2' => $var2, 'var5' => $var5));
                if ($ret === false) {
                    $err = $InsertLine->errorInfo();
                    echo 'Erreur Insert: ' . $err[2];
                }
            }
            // Fin CountLine->1
            if ($CountLine == 0) {
                $ret = $InsertLine->execute(array(
                    'var1' => $var1, 'var2' => $var2, 'var3' => $var3, 'var4' => $var4, 'var5' => $var5));
                if ($ret === false) {
                    $err = $InsertLine->errorInfo();
                    echo 'Erreur Insert: ' . $err[2];
                }
            } // Fin CountLine->0
        }
        // Fin Foreach
    }
}
?>
ensuit suivant le volume des fichier il peux être intéressant de faire faire le boulot par le sgbd si cela est possible, genre un load data in file avec mysql, ou avec oracle du code (et surement d'autre) du code pl qui va parser le fichier.

Il faut voir si des procédures stockées ne serait pas plus performant que des requêtes préparées.
A tester


@+

Re: Optimisation d'un code php / requêtes mysql.

par J-oxi » 24 mai 2013, 19:07

En effet, mais cette boucle se trouve aussi dans une boucle
$MaxExe = 50;
for($c=1;$c<=$MaxExe;$c++){
// Définition de la base de données, table pour la connexion.
foreach(....){
// Code précedent
  }
}
Est ce que cela améliorera beaucoup le temps d’exécution?

Re: Optimisation d'un code php / requêtes mysql.

par moogli » 24 mai 2013, 18:40

Salut,

Commence par sortir les prepare de la boucle c'est a ça que sert une requête préparée !
La tu redeclare la requête préparée a chaque ligne c'est inutile.

@+

Optimisation d'un code php / requêtes mysql.

par J-oxi » 24 mai 2013, 17:32

Bonjour,
Je bloque depuis quelques temps sur un code php. Celui-ci doit récupérer les lignes d'une source, vérifier si elles existent en base de données, Mettre à jour si elles existent ou insérer si elles n'existent pas.

Pour cela j'ai écris le code suivant :
<?php
$db = FonctionConnBdd();
$Source = "http://urlsource.fr/fichier.txt";
if(!is_array($Source)){
echo "Erreur Source";
}
foreach($Source as $src){
		list($var1, $var2, $var3, $var4, $var5) = explode(',', $src);
		// Vérification de la présence dans la base
		$TryLine = $db->prepare("SELECT id FROM Matable WHERE var1=:var1 AND var2=:var2");
		$TryLine->execute(array('var1'=>$var1,'var2'=>$var2));
		$CountLine = $TryLine->rowCount();
		$TryLine->closeCursor();
		// Si existant -> update
		if($CountLine == 1){
			$UpdateLine = $db->prepare("UPDATE Matable SET var5=:var5 WHERE var1=:var1 AND var2=:var2");
			$UpdateLine->execute(array('var1'=>$var1,'var2'=>$var2,'var5'=>$var5));
			if(!$UpdateLine){
				echo "Erreur Update";
			}
			$UpdateLine->closeCursor();
		}// Fin CountLine->1
		// Si n'existe pas -> Insert
		if($CountLine == 0){
			$InsertLine = $db->prepare("INSERT INTO Matable (id,var1,var2,var3,var4,var5) VALUES (:id,:var1,:var2,:var3,:var4,:var5)");
			$InsertLine->execute(array(
			'id'=>'','var1'=>$var1,'var2'=>$var2,'var3'=>$var3,'var4'=>$var4,'var5'=>$var5));
			if(!$InsertLine){
				echo "Erreur Insert";
			}
			$InsertLine->closeCursor();
		} // Fin CountLine->0
}// Fin Foreach
?>
Toutefois, le fichier source peut contenir plus de 100.000 lignes. Donc le processus est très long. (probablement du fait de l'accompagnement d'autres fonctions avant et après le code présent ci-dessus)
Je me demandai donc s'il y'avait possibilité d'optimiser le code afin de gagner en temps d’exécution.

Merci pour vos réponses.