{MySQL} Base de donnée trop lente

Fermé
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011 - 11 août 2009 à 11:09
Archeus01 Messages postés 1567 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 9 juin 2022 - 13 août 2009 à 11:33
Bonjour à tous,

Je vous explique mon problème. Je suis actuellement en train de créer un site internet.
Pour le bon fonctionnement de celui-ci, je dois créer un "module" de recherche par autocompletion pour définir un lieu de départ et un lieu d'arrivée. Jusque là ça va ^^
Par contre là ça se corse ;-) En effet, pour cette autocompletion, je vais rechercher dans la base de donnée toutes les villes et villages existants (environ 2600000 ^^).
Donc mon "module" de recherche fonctionne, mais il est beaucoup trop long.

J'aurai donc aimé savoir si quelqu'un avait déjà fait face à ce genre de problème, et si oui, comment le résoudre ?

Pour info: Je suis actuellement en locale (j'ose même pas imaginer le temps que ça prendra une fois msi en ligne) et j'utilise wamp (phpmyadmin, mysql).

Merci à tous ceux qui pourront m'aider.
Bonne journée
Mayous
A voir également:

17 réponses

Archeus01 Messages postés 1567 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 9 juin 2022 447
13 août 2009 à 11:33
Bonjour, j'ai bien regardé...
Le meilleur moyen est d'utiliser PDO (sans parler de tous les avantages dont tu n'as pas besoin immédiatement).
(lien vers les explications pour chaque fonction : http://fr3.php.net/manual/fr/book.pdo.php )

/* Connexion à une base ODBC avec l'invocation de pilote
C'est cette partie qu'il va falloir que tu modifies
 */

$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
/*fin de la partie à modifier*/

try {
    $dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
    echo 'Connexion échouée : ' . $e->getMessage();
}
$query = 'SELECT `Villes` FROM `villes` LIMIT 0,10'; 
$sth = $dbh->prepare($query);
$sth->execute();

/* Récupération de toutes les valeurs de la première colonne */
$ville= $sth->fetchAll(PDO::FETCH_COLUMN, 0);

Voila, la tu as EXACTEMENT le $ville que tu avais à la fin de ton while.

Ton foreach a trop de tests à l'intérieur! Pourquoi ne pas faire un truc du genre
$query = "SELECT `Villes` FROM `villes` where `Villes` like '".$_POST['ville']."%' LIMIT 0,".$MAX_RETURN; 
$sth = $dbh->prepare($query);
$sth->execute();

/* Récupération de toutes les valeurs de la première colonne */
$ville= $sth->fetchAll(PDO::FETCH_COLUMN, 0);
echo "<ul>\n"; 
foreach ($villes as $ville)
{
if ($i<$MAX_RETURN && stripos($ville, $_POST['ville']) === 0)
{
echo (utf8_encode(" <li>$ville</li>\n")); 
}
echo "</ul>"; 


En plus faire un foreach la avec le $i était TRES MAL! Imagine $ville est un tableau à 26 000 lignes, MAX_RETURN est égal à 10, tu vas faire 25990 fois le test pour rien!

Alors que tu auras fait un truc du genre,
echo "<ul>\n";
$MAX_RETURN = 10;
$i = 0;
while ($i++ < $MAX_RETURN)
{
if stripos($ville, $_POST['ville']) === 0)
{
echo (utf8_encode(" <li>$ville</li>\n"));

}
}
echo "</ul>";

Sa aurait déjà été beaucoup mieux !
Après si tu as besoin d'un tableau ville ne correspondant pas à ton srtpos pour autre chose, le mieux est de faire deux requêtes avec pdo, avec la secodne pour ne pas avoir à faire le test str_pos (donc utiliser le where... like .. dans ta requête). Mais je donne pas ce code là, avec ce que j'ai donné, tu devrais facilement pouvoir le faire.


Ces codes n'ont pas été testés donc il peut manquer des ;, y avoir des erreurs de syntaxes mais les idées sont défendables.

Pour ceux qui vont me dire que le coup du str_pos, c'est du code métier, ect.; à ceux la je dirais : vous avez vu ou est fait la requête SQL? Donc venez pas m'embêter avec ça :) .
1
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
11 août 2009 à 15:09
Hello,
pourrais-je avoir la structure complete de la table contenant 260000...lignes, le nombre total d'enregistrements, identifier les clés primaires et étrangère si besoin...

Je vais essayer de te proposer une soluce.
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
11 août 2009 à 16:16
Tout d'abord merci moderno31,

Voici le lien renvoyant à l'image de la table "villes" de ma base de données :

http://img256.imageshack.us/img256/5126/bdd.jpg

Voila, en gros la clé primaire est le champ id_villes.
Je fait une requête SQL en php pour venir chercher les informations dans cette base.

Si tu as besoin d'autres informations n'hésites pas.

Mayous
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
11 août 2009 à 17:56
Quel volume...
Tu y as rentrés toutes les villes de france ?
Je te conseillerais de mettre un index sur les pays et les noms des villes.
Aussi de passer tes champs longitude et latitude en float avec les bonnes précisions qui te conviennes. regarde sur le web la syntaxe exactement.

Peux-tu me donner un ou plusieurs exemple de requetes que tu fais via PHP qui pose un problème de temps.
Il se peut que le souci vienne de la requete.
Passe la moi la plus complete possible.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
11 août 2009 à 20:16
Merci encore moderno31,

Alors, que veux tu dire par mettre en index?

Il n'y a pas que toute les ville francaise, mais toutes les villes et villages mondiaux, donc en effet ça fait un paquet ;-)

Voici un exemple de requête :

@mysql_connect('XXXXXX', 'XXXXXX', 'XXXXXXX') or die('Connexion à la base de données impossible');
@mysql_select_db('XXXXXX') or die('base de données inexistante');

$query = 'SELECT `Villes` FROM `villes` LIMIT 0,10';

$result = mysql_query($query) or die('problème mysql');

$villes = array();

while($tableau = mysql_fetch_array($result) )
{
$villes[] = $tableau['Villes'];
}


echo "<ul>\n";
$MAX_RETURN = 10;
$i = 0;
foreach ($villes as $ville)
{
if ($i<$MAX_RETURN && stripos($ville, $_POST['ville']) === 0)
{
echo (utf8_encode(" <li>$ville</li>\n"));
$i++;
}
}
echo "</ul>";


J'ai ajouté dans la requête LIMIT 0,10, ce qui accélère grandement pour les ville commençant par a, mais pour la suite, c'est toujours très long ...

Merci encore pour l'aide que tu me fournis ;-)

Mayous
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
11 août 2009 à 20:37
D'accord.
Pour l'index il faut en créer un dans l'interface PHPMyADMIN.
En mode structure tu as la rubrique index, tu as les colonnes suivantes (Nom de la clé Type Cardinalité Action Champ )
Là il te faut ajouter une clef sur un/plusieurs champ(s), tu seras amené à choisir les champs sur lesquels tu veux positionner un index et tu fais sauvegarder.

Dit moi sinon, ta requete permet de faire quoi ? Parce que tu appelles tous les enregistrements de ta table avec la requete.
En résumé je veux savoir l'usage que tu fais des données que tu sélectes en base..
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
11 août 2009 à 21:28
Alors, les données que je récupère sont ensuite utilisées avec la librairie scriptaculous en javascript.
Celle-ci me permet de réaliser une autocompletion sur toutes les villes du monde.
C'est pourquoi j'ai besoin d'autant de données.

Sinon pour l'index je vois, mais quel en ai l'utilité? je ne connais pas cette possibilité.

Merci à toi.

Mayous
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
11 août 2009 à 21:42
J'ai jamais bien compris le mécanisme (techniquement). Par le code je ne sais pas les mettre en place.
Je ne sais le faire que par l'interface comme je t'ai montré.
Maintenant je n'ai jamais eu autant de volume à traiter. Donc je les met mais s'il ny en avait pas ça serait pareil.

En gros lors de requetes, avec recherches sur des champs de type varchar ça va plus vite.
Maintenant tout dépend de la taille de ta variable qui récupère tous ces résultats.

Je ne maitrise pas les histoires de librairies.

J'espère t'avoir aidé
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
11 août 2009 à 22:41
Merci beaucoup moderno.

En fait, après de multiples essais, dans tout les sens possibles, je ne pense pas pouvoir accélérer mes requêtes, mis a part en séparant totalement ma table (par ordre alphabétique), et en le faisant sur plusieurs termes (un boulot monstre ^^).
Je vais donc m'adapter au mieux, sans doute faire autrement, genre une autocompletion sur le pays, puis un champ texte simple pour entrer le ville, et enfin après validation, des propositions a l'utilisateur pour une bonne correspondance. Un peu du genre google map.

Merci encore pour ton aide
Bonne continuation
Mayous
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
12 août 2009 à 09:14
Hello,
Petit test à faire. Exécute la meme requete directement sur la base et ensuite par l'intermédiaire de php. Compare les durées.
Comment tu t'es organisée pour faire de l'autocompletion : ça m'interesse !
Tu peux m'expliquer?

Tant mieux si j'ai pu t'aider. Rappelle moi quand tu veux
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
12 août 2009 à 09:49
J'ai fait le petit test.
Alors le "select Villes from villes" est très rapide sur phpmyadmin.
Mon problème provient sans doute de la boucle while que j'utilise (je n'ai pas le choix).
En effet, les données reçues lors d'une requête comme celle-ci sur mysql non sont pas un tableau, or pour pouvoir travailler dessus il me faut un tableau (array).

Pour l'autocompletion, c'est plutôt simple en fait.
Il te faut les librairies scriptaculous (une parmi tant d'autres ^^).
Dans ton html tu fait appelle à certaines de ces librairies, et tu créer ton formulaire, dans lequel les id seront réutilisé. Tu créer aussi un petit javascript très simple dans lequel tu initialises scriptaculous ajax.autocompleter.
C'est dans cette initialisation que tu récupères le mot ou la lettre entrée par l'utilisateur, ainsi que le fichier php dans lequel tu récupèreras uniquement le tableau des valeurs extraite de mysql. Le fichier php renvois aussi les différentes suggestions.
Bon je sais c'est un peu compliqué et fouillis comme explication ^^
Pour mieux comprendre, je te conseil d'aller là :
https://www.j0k3r.net/ajax-une-autocompletion-avancee-en-ajax
(il y a même le code source avec ;-))

Merci de ton aide, si tu as des questions pour l'autocompletion je suis à ta disposition.
Et si tu as une autre idée pour mon problème ... ^^
Mayous
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
12 août 2009 à 16:14
Merci pour l'info d'autocomplétion. Quand l'idée aura bien fait son chemin dans ma tête j'essaierai de la mettr en oeuvre.
Je ne suis doué avec les truc en Ajax...lol
Heu, juste tu peux me faire voir la page qui réalise le traitement ?
Une fois la requete envoyée au serveur, et qu'il t'a répondu, montre moi ce que tu fais. La variable qui récupère les infos de ta base est déjà un tableau. Puisque ta boucle va la parcourrir...
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
12 août 2009 à 16:21
Alors il y a un fichier js que j'ai réalisé (très simple), qui permet de faire le lien entre ce que l'utilisateur met dans le champ, la gestion de l'autocompletion par la bibliothèque js, ainsi que l'appelle à l'utilisation des fichier php.
Dans les fichiers php, il y a le code que j'ai mis plus haut (4eme réponse).
Et dans le fichier js :

var init = function ()
{
// Instanciation de la classe Autocompleter
new Ajax.Autocompleter(
"pays_depart", // id du champ de formulaire
"pays_departs_propositions", // id de l'élément utilisé pour les propositions
"autocompleter-exemple-1-serveur.php", // URL du script côté serveur
{
paramName: 'pays_depart', // Nom du paramètre reçu par le script serveur
minChars: 1 // Nombre de caractères minimum avant que des appels serveur ne soient effectués
});
}

Cette fonction est appelée dans le fichier d'index html qui lui envois la donnée principale "pays_départs".
Après, la page qui réalise le traitement, je vais essayer de la retrouver dans les librairies spectraculous, mais je ne te promet rien ;-)
Voila, j'espère avoir répondu à ta question
0
moderno31 Messages postés 870 Date d'inscription mardi 23 juin 2009 Statut Membre Dernière intervention 8 août 2012 92
12 août 2009 à 16:31
ah oui excuse moi. Le code y était déjà : vrai.
Je ne sais pas ce qu'il faudrait faire de mieux pour accelérer le traitement.

Moi quand je me sers de while, je fais comme ça. J'appelle pas de array et tout le truc

while ($return_identity = mysql_fetch_array($result_sql_identite)) {
echo($return_identity['Nom']);
echo($return_identity['Titre']);
echo("<br/>");
}
Et ça fonctionne super.

Bon courage merci pour tes infos
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
12 août 2009 à 16:52
Oui c'est la première technique que j'ai voulu utiliser pour le while, le truc c'est qu(il me fallait absolument les résultats dans un array.
Or avec cette technique, ce n'est pas le cas.
Donc il m'a fallut faire autrement pour que mes valeurs soient stockées dans un tableau.

De rien pour les infos, et merci à toi d'avoir essayé de m'aider.
N'hésites pas plus tard si tu as d'autres questions en ce qui concerne l'autocompletion ;-)
0
Archeus01 Messages postés 1567 Date d'inscription mercredi 3 octobre 2007 Statut Membre Dernière intervention 9 juin 2022 447
12 août 2009 à 17:07
Bonjour, tu as quoi exactement dans ton while, que je peux peut-être t'aider à ce niveau la...
0
Mayous29 Messages postés 38 Date d'inscription mardi 11 août 2009 Statut Membre Dernière intervention 25 février 2011
12 août 2009 à 17:26
Bonjour Archeus01,
Alors tu peux voir mon code qui lit dans la base de données, ainsi que le while ensuite pour mettre les valeurs dans un tableau sur mon message précédent (4eme réponse ;-)).

Merci pour tout l'aide que tu pourras m'apporter.

Mayous
0