IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PHP & Base de données Discussion :

Optimisation de code SQL et php


Sujet :

PHP & Base de données

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 71
    Points : 72
    Points
    72
    Par défaut Optimisation de code SQL et php
    Bonjour à tous

    J’ai un bout de code qui fonctionne très bien, mais qui est très très lent (25 sec).

    J’ai indexé la table et j’ai gagné 1 sec, youpi : )

    J’essai d’optimiser le code mais je ne trouve pas de solution, je pause cette question dans la parti mysql car je pense qu’on peut simplifier le tout avec DELETE WHERE NOT EXISTS, mais je n’y arrive pas.

    Si vous avez des idées je suis preneur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?php
    	$sql = "SELECT id_data FROM `table1`";
    	$req = mysql_query($sql);
    	while ($arr = mysql_fetch_array($req, MYSQL_ASSOC))
    	{
    	        $ide = " SELECT  `name` FROM `table2` WHERE `value`='".$arr['id_data']."'";
    	        $result = mysql_query($ide);
    	        $arr2 = mysql_fetch_array($result, MYSQL_ASSOC);
    	        if (!$arr2){
    		        $reqdel = "DELETE FROM `table1` WHERE `id_data` = '".$arr['id_data']."'";
                  mysql_query($reqdel);
    	        }
    	}
    ?>

  2. #2
    Membre averti

    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2011
    Messages
    205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2011
    Messages : 205
    Points : 409
    Points
    409
    Billets dans le blog
    1
    Par défaut
    A voir ce qui est le plus optimisé selon la taille de tes tables, mais tu as plusieurs moyens d'optimiser :
    - si tes tables sont petites, DELETE FROM `table1` WHERE `id_data` NOT IN (SELECT value FROM `table2`) ?

    - pour tes tables plus grosses et, surtout, si tu souhaites garder un traitement côté PHP - pour ajouter des logs, un contrôle, etc -, faire du traitement par lots avec des requêtes préparées ( introduction à PDO et requêtes préparées).
    Cette méthode te permettra de traiter des lots de 50 (par exemple, à adapter selon ton serveur et ta bdd) éléments avec des requêtes pour lesquelles le moteur aura déjà calculé le plan d'exécution => gain de temps

    Tu peux aussi récupérer tous tes identifiants à supprimer dans un tableau et lancer ta requête de suppression à la sortie de ta boucle (plutôt que de faire un DELETE à chaque tour de boucle).
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    <?php
        $tabToDelete = array();
        $sql = "SELECT id_data FROM `table1`";
        $req = mysql_query($sql);
        while ($arr = mysql_fetch_array($req, MYSQL_ASSOC))
        {
            $ide = " SELECT  `name` FROM `table2` WHERE `value`='".$arr['id_data']."'";
            $result = mysql_query($ide);
            $arr2 = mysql_fetch_array($result, MYSQL_ASSOC);
            if (!$arr2){
                $tabToDelete[] = $arr['id_data'];
            }
        }
        if (!empty($tabToDelete))
        {
            $reqdel = "DELETE FROM `table1` WHERE `id_data` IN '".implode(',', $tabToDelete)."'";
            mysql_query($reqdel);
        }
    ?>

  3. #3
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Salut,

    il faut fuir les requêtes imbriquées comme la peste.
    La solution réside dans le design de ta base :
    - quel est le type des tables utilisées : MyISAM, InnoDB...

    Ensuite les solution à base de IN sont très lentes car cette clause induit une lecture séquentielles des données.

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 71
    Points : 72
    Points
    72
    Par défaut
    Citation Envoyé par k'amm Voir le message
    A voir ce qui est le plus optimisé selon la taille de tes tables, mais tu as plusieurs moyens d'optimiser :
    - si tes tables sont petites, DELETE FROM `table1` WHERE `id_data` NOT IN (SELECT value FROM `table2`) ?

    - pour tes tables plus grosses et, surtout, si tu souhaites garder un traitement côté PHP - pour ajouter des logs, un contrôle, etc -, faire du traitement par lots avec des requêtes préparées ( introduction à PDO et requêtes préparées).
    Cette méthode te permettra de traiter des lots de 50 (par exemple, à adapter selon ton serveur et ta bdd) éléments avec des requêtes pour lesquelles le moteur aura déjà calculé le plan d'exécution => gain de temps

    Tu peux aussi récupérer tous tes identifiants à supprimer dans un tableau et lancer ta requête de suppression à la sortie de ta boucle (plutôt que de faire un DELETE à chaque tour de boucle).
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    <?php
        $tabToDelete = array();
        $sql = "SELECT id_data FROM `table1`";
        $req = mysql_query($sql);
        while ($arr = mysql_fetch_array($req, MYSQL_ASSOC))
        {
            $ide = " SELECT  `name` FROM `table2` WHERE `value`='".$arr['id_data']."'";
            $result = mysql_query($ide);
            $arr2 = mysql_fetch_array($result, MYSQL_ASSOC);
            if (!$arr2){
                $tabToDelete[] = $arr['id_data'];
            }
        }
        if (!empty($tabToDelete))
        {
            $reqdel = "DELETE FROM `table1` WHERE `id_data` IN '".implode(',', $tabToDelete)."'";
            mysql_query($reqdel);
        }
    ?>
    Merci la version php, elle ma fait gagné 7 sec, ce qui est un vrais changement.

    Je vais regarder pour les autres points que tu as dit

    Pour information c'est du MyISAM il y a 86 602 ligne et la table fait 3Mo, je ne suis pas obliger de garder un traitement php (j'aimerai même éviter)

  5. #5
    Expert éminent sénior
    Avatar de rawsrc
    Homme Profil pro
    Dev indep
    Inscrit en
    Mars 2004
    Messages
    6 142
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Dev indep

    Informations forums :
    Inscription : Mars 2004
    Messages : 6 142
    Points : 16 545
    Points
    16 545
    Billets dans le blog
    12
    Par défaut
    Et avec ça :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    DELETE 
      FROM table1 
           LEFT JOIN table2 ON table1.id_data = table2.name
     WHERE 
           table2.name IS NULL
    N'oublie pas de poser des index sur les colonnes de jonction.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Développeur C++
    Inscrit en
    Avril 2012
    Messages
    771
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur C++
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 771
    Points : 1 631
    Points
    1 631
    Par défaut
    Bonsoir,

    il me semble qu'il n'est pas possible d'utiliser des jointures lors de l'utilisation de la commande DELETE.

    Il va falloir passer par la syntaxe que k'amm a donné plus haute :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    DELETE FROM maTable1 WHERE idData NOT IN (SELECT idDate FROM matable2 ...)

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 71
    Points : 72
    Points
    72
    Par défaut
    Je vous confirme que le lef join est possible dans un delete, je continue mes investigations.

  8. #8
    Membre expérimenté
    Homme Profil pro
    Développeur C++
    Inscrit en
    Avril 2012
    Messages
    771
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur C++
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 771
    Points : 1 631
    Points
    1 631
    Par défaut
    Après lecture de la doc au sujet des jointures avec l'utilisation du DELETE,

    il est précisé qu'il faut préciser les tables qui seront concerné par la suppression d'enregistrement avant la clause FROM :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    DELETE table1 FROM table1
    LEFT JOIN table2 ON table1.id = table2.id;

    si on veut supprimer dans table1, table2 mais que l'on a besoin d'information dans table3 :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    DELETE t1, t2 FROM table1 t1
    LEFT JOIN table2 t2 ON t1.id = t2.id
    LEFT JOIN table3 t3 ON t2.nom = t3.nom
    WHERE t3.col IS NULL;

    lien vers la doc.

Discussions similaires

  1. Optimisation du code PHP vs SQL
    Par persia dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 18/11/2010, 20h10
  2. Optimisation du code SQL
    Par JeanNoel53 dans le forum InterBase
    Réponses: 1
    Dernier message: 02/07/2010, 11h31
  3. [SQL - procStock ] optimisation du code (éviter les boucles)
    Par luimême dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 06/10/2005, 17h22
  4. [ SQL - proc stockée ] optimisation du code parcours curseur
    Par luimême dans le forum Langage SQL
    Réponses: 1
    Dernier message: 06/10/2005, 16h20
  5. Optimisation du code des ordres SQL
    Par Titouf dans le forum Langage SQL
    Réponses: 1
    Dernier message: 14/08/2005, 22h08

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo