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 :

Performance sur un grand enchainement de requête select avec php et mysql


Sujet :

PHP & Base de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    ingénieur en automatique
    Inscrit en
    Avril 2013
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur en automatique
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2013
    Messages : 59
    Par défaut Performance sur un grand enchainement de requête select avec php et mysql
    onjour,

    J'ai réalisé un logiciel en C# et Sqlite pour m'aider au jeu "4 images et 1 mot", et ça fonctionne plutôt pas mal.

    Afin de pouvoir partager mon outil et avoir quelque chose de multiplateforme j'ai décidé d'en faire une version web et tout coder en php avec Mysql.

    Le principe est simple, j'ai créé une table contenant plus de 700 000 mots de la langue française (elle contient les variantes, verbes et adjectifs quand c'est le cas pour chaque mot de base rassurez vous!), qui est constituée du mot, de sa taille et de sa signature: une colonne pour chaque caractère (donc 26) + une pour les jokers (j'inclus les espaces, tirets et apostrophes etc.). et pour chaque colonne je renseigne le nombre de fois où le caractère apparait dans le mot... exemple: coco -> a = 0, b = 0, c = 2, d = 0 [...] o = 2, [...] z = 0

    Pour chaque planche du jeu 4 img et 1 mot, on a un jeu de lettres proposés et une taille de mot (plus petite que le jeu de lettres).

    Je calcule donc l'ensemble des combinaisons alliant le jeu de lettre et la taille du mot (pas les permutations, c'est important pour les performances) et pour chaque combinaison je génére la signature, chaque signature étant stockée j'ai ensuite un beau tableau... et donc

    il suffit de faire avec sql un sélect pour chaque signature de combinaison avec en clé supplémentaire la taille du mot, et de récupérer les mots qui correspondent, et cela avec l'ensemble des combinaisons pour avoir le mot qu'on doit trouver dedans (ensuite c'est l'humain qui a l'aide des images indices fait le tri).

    ça marche bien, par contre j'ai un facteur 10 niveau performance entre mon appli C# (la plus rapide) et mon appli Php, et j'aimerais savoir comment optimiser ça.

    pour un mot de 6 lettres dans la séquence iqnafpgdelru, il y a 924 combinaisons à tester, en C# ça me prend 2'10, en Php il m'a fallu plus de 22'.

    En C# je fais continuellement des ouvertures/fermeture de la base (un fichier Sqlite pour rappel... je pense pas que ce soit aussi performant qu'un sgbd) pour chaque combinaison, en Php avec Mysql j'utilise les requêtes préparées et je déclare un seul objet PDO que j'utilise du début à la fin, et malgré ça les résultats sont une catastrophe...

    Une idée?

    Code de ma fonction de recherche de mots:

    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
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    public static function fetchWords2($signs,$size) // $signs est un 2dim tableau, chaque élément est un tableau qui a la signature d'un mot, $size est un int
        {
     
           // query de la requête préparée
            $reqselsign = "select * from word where length=? and a=? and b=? and c=? and d=? and e=? and f=? and g=? and h=? and i=? and j=? and ";
            $reqselsign .= "k=? and l=? and m=? and n=? and o=? and p=? and q=? and r=? and s=? and t=? and u=? and v=? and w=? and x=? and y=? and   z=?;";
     
     
            if(!isset($size) or $size <2 or !isset($signs))
                return array();
     
            try
            {
                $db = new PDO(self::$connectionstring, self::$username, self::$pwd);
            }
            catch(Exception $e)
            {
                die('DB error, stop! : '.$e->getMessage());
            }
     
            $wordslist = array(); // notre tableau de liste des mots à retourner à la fin
            $req = $db->prepare($reqselsign);
     
     
     
     
            foreach($signs as $signa) // pour chaque sous-tableau "signature d'un mot" $signa
            {
     
     
                // $param est la liste des paramètres de ma requête, sur plusieurs lignes uniquement pour plus de visibilité
     
                $param = array($size,$signa["a"],$signa["b"],$signa["c"],$signa["d"],$signa["e"],$signa["f"],$signa["g"],$signa["h"],$signa["i"],$signa["j"],$signa["k"]);
                $param = array_merge($param, array($signa["l"],$signa["m"],$signa["n"],$signa["o"],$signa["p"],$signa["q"],$signa["r"],$signa["s"],$signa["t"]));
                $param = array_merge($param, array($signa["u"],$signa["v"],$signa["w"],$signa["x"],$signa["y"],$signa["z"]));
     
     
     
                $req->execute($param);
     
                while ($data = $req->fetch())
                {
                    $wordslist[] = $data["name"]; // récupérer le mot stocké dans la colonne name et l'ajouter à notre liste résultat
                }
     
                $req->closeCursor();
            }       
     
     
     
            return $wordslist;
     
     
        }

  2. #2
    Membre Expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Billets dans le blog
    8
    Par défaut
    Je suppose que tu veux parler de secondes ('') plutôt que de minutes (')

    N'utilise pas 'or' en PHP, juste en SQL. Sinon tu auras de très mauvaises surprises.
    Essaie avec cette condition...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if( empty($size) ||  empty($signs) || (! empty($size) && $size <2 )){
       return false;
    }
    //puis ensuite tu déroules ton code, tranquille.
    PDO, une soupe et au lit !
    Partir de la fin est un bon moyen de retrouver son chemin. Bibi - 2020

  3. #3
    Membre confirmé
    Homme Profil pro
    ingénieur en automatique
    Inscrit en
    Avril 2013
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur en automatique
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2013
    Messages : 59
    Par défaut
    Salut,

    merci, pourquoi || et pas or? J'imagine que c'est du coup aussi && à la place de and?
    J'avoue qu'il y a 2 jours j'y connaissais rien en php, j'avais lu un tuto sans accrocher il y a 10 ans... puis je suis devenu ingénieur et pas le choix, j'ai appris C++, Java, C# puis Python, et là Php m'a par d'un coup très facile, mais je connais pas encore les subtilités...

    Sinon je te confirme bien que c'est des minutes... et le lag vient bien de la communication avec la base de données (le code que j'ai écrit dans mon premier message), la génération des combinaisons ne prends que quelques millisecondes à côté... donc j'aimerais optimiser cette chose car je comprends pas qu'un programme utilisant SQL derrière un système de fichier puisse être plus rapide que quand il s'agit d'un Sgbd, et c'est pourtant le cas...
    C# une fois compilé en bytecode est peut être plus rapide que l'interprétation brut de Php par Apache... mais 2 minutes VS 22 minutes... il doit y avoir autre chose.

  4. #4
    Membre Expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Billets dans le blog
    8
    Par défaut
    Teste d'abord, je t'expliquerai après, si ça fonctionne.
    Sinon, il faut absolument poser des indexes dans ta table sur les 26 lettres.
    Aussi, évite le * dans une requête SQL quand tu fais tourner ta méthode dans une boucle. Mets directement tous les champs qui t'intéressent.
    Sinon, tu vas convoquer une méta requête (pour aller chercher tous tes champs justement) totalement inutile à chaque tour.
    Et enfin un dernier conseil...
    filtre dans l'ordre du plus rare au plus fréquent des fréquences de lettres
    Z, W, K, Y etc.... avec A, U, O, I, E en dernier...
    Ca devrait rendre les performances meilleures, et pas qu'un peu.
    PDO, une soupe et au lit !
    Partir de la fin est un bon moyen de retrouver son chemin. Bibi - 2020

  5. #5
    Membre Expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Billets dans le blog
    8
    Par défaut
    Je vais être honnête, je ne comprends pas bien ce que tu mets à la place de tes marqueurs à l'arrivée, et le concept de "signature" du mot.
    Soyons concret

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    select * from word where length=? and z=? and y=? and k=? and w=? /*etc*/
    Pourrais-tu me donner une exemple de par quoi tu remplaces tes points d'interrogation, quand la lettre est présente, quand la lettre est absente ?

    Edit : est-ce que fondamentalement, on part un peu du même principe que le jeu du pendu ?
    PDO, une soupe et au lit !
    Partir de la fin est un bon moyen de retrouver son chemin. Bibi - 2020

  6. #6
    Membre Expert
    Avatar de Dendrite
    Femme Profil pro
    Développeuse informatique
    Inscrit en
    Juin 2008
    Messages
    2 129
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 59
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeuse informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2008
    Messages : 2 129
    Billets dans le blog
    8
    Par défaut
    Bon, je me réponds toute seule, je suis allée voir, oui, c'est fondamentalement le même principe que le jeu du pendu.

    Je ne vois pas à quoi sert ta table abcdef...

    Je ferais le traitement en PHP.
    En mettant en session les lettres déjà trouvées pendant la session du joueur. C'est peut-être la notion qui te manque dans le langage PHP, et qui est indispensable.
    session = variable qui ne doit pas disparaître à chaque rafraîchissement de page, mais ne doit pas non plus forcément persister au point d'être stocké en base...

    Voici les grandes lignes de l'algo que je te propose, et qui devrait offrir une excellente performance.

    D'abord côté SQL, tu n'aurais que 3 tables :

    vocabulaire (id, mot) unicité mot, 700 000 tuples si j'ai bien compris
    joueur(id, login, mdp) unicité login,
    jeu(id, joueur_id, vocabulaire_id, score) unicité du couple joueur_id + vocabulaire_id

    Ensuite en PHP

    1) mettre en session l'id du joueur $_SESSION['joueur_id'],
    le mot choisi aléatoirement dans ta table n_vocabulaire $_SESSION['cible'] (prenons 'callipyge'), et qui n'est pas déjà dans ta table jeu pour ce joueur,

    Enfin, une dernière variable de session qui déterminera ton algo pendant le déroulement du jeu.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $_SESSION['tentatives']=array();
    Mettons que le joueur ait droit à 10 tentatives maxi
    et qu'à la première, il te propose "L"

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $_SESSION['tentatives'][]= array ('mot'=> NULL, 'lettre' => 'L', 'nb' => 2);
    Mettons qu'il soit très fort, et que dès la deuxième tentative, il saisisse le bon mot !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $_SESSION['tentatives'][]=array ('mot'=> 'CALLIPYGE', 'lettre' => NULL, 'nb' => 9);
    Quand il a gagné, tu saisis dans ta table jeu les 3 données qui t'intéressent, le score final étant count($_SESSION['tentatives']) puis tu réinitialises toutes tes variables de session.

    Voilà, la suite, tu connais, des histoires de connexion à la base, de boucles et de conditions.

    Sinon

    j'ai créé une table contenant plus de 700 000 mots de la langue française
    Tu as obtenu ça gratuitement ? Je rêve d'avoir ça...
    PDO, une soupe et au lit !
    Partir de la fin est un bon moyen de retrouver son chemin. Bibi - 2020

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème sur requête select avec les caractères spéciaux
    Par Julien698 dans le forum Développement
    Réponses: 3
    Dernier message: 06/08/2015, 14h08
  2. [MySQL-5.5] Performance sur l'union de sous-requêtes
    Par flashguitou dans le forum Requêtes
    Réponses: 9
    Dernier message: 30/06/2013, 20h39
  3. faire une condition IF sur le resultat d"une requête select
    Par realwail dans le forum Développement Web avec .NET
    Réponses: 1
    Dernier message: 21/10/2010, 09h35
  4. Requête SELECT avec jointure sur deux tables
    Par bud64 dans le forum Requêtes
    Réponses: 6
    Dernier message: 01/10/2010, 14h06
  5. Requête select avec jointure sur des enregistrements inexitant.
    Par faistoiplaisir dans le forum Langage SQL
    Réponses: 2
    Dernier message: 06/11/2009, 17h36

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