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

Bases de données Delphi Discussion :

Problème de délais de recherche d'une requete


Sujet :

Bases de données Delphi

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2014
    Messages : 9
    Points : 8
    Points
    8
    Par défaut Problème de délais de recherche d'une requete
    bonjour;
    j'utilise un table qui contiens 8000 enregistrement. lorsque j’exécute la requête j'obtiens une réponse dont le délais varie de 1 a 20 seconde, c'est a dire que pour la même requête des fois j'obtiens mois de 1 seconde comme temps de réponse et des fois ça va aller jusqu'à 20 secondes.
    voici la requete que j'utilise :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    ADOQuery1.SQL.Clear;
    ADOQuery1.SQL.Add('select * from matable where Champs = :mon_parametre');
    ADOQuery1.Parameters.ParamByName('mon_parametre').Value := Edit1.Text;
    ADOQuery.Open;
    while not ADOQuery.Eof do
      begin
      ListBox1.Items.Add(ADOQuery1.FieldByName('monchamps').AsString);
      ADOQuery1.Next;
      end;
    pourquoi il y a cette variabilité de délais de réponse "pour la même requête"?
    y-a-il un moyen pour fixer le délais a une très courte durée?

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Bonjour,

    plusieurs pistes pour améliorer :
    1- essayer de faire un préparation de la requête (prepare)
    2- s'assurer que le champ soit indexé

    * autres
    si possible s'il s'agit d'un traitement répétitif et sauf s'il sagit d'un ADOQuery créer au runtime (pas indiqué), éviter le clear
    ne pas oublier le close après traitement (surtout sur les BDD <- encore non indiqué gérant les transactions)

    bref, en gros
    close
    clear <- pas obligatoire si SQL.Text:=
    if prepare then unprepare
    sql.add()
    sql.add()
    ou SQL.Text:=
    prepare
    (parametres
    open
    traitement
    close) * n
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2014
    Messages : 9
    Points : 8
    Points
    8
    Par défaut
    j'utilise le composant ADOQuery et je voie pas de "prepare" dedans

    j'ai mis close au début mais lorsque je valide ma requête après un certain nombre de fois " 4 ou 8" j'obtiens un délais très long , des fois ça arrive dès la 1ere fois!!!

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    566
    Détails du profil
    Informations personnelles :
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2009
    Messages : 566
    Points : 1 045
    Points
    1 045
    Par défaut
    Bonjour,

    A l'examen de ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ADOQuery1.SQL.Clear;
    ADOQuery1.SQL.Add('select * from matable where Champs = :mon_parametre');
    ADOQuery1.Parameters.ParamByName('mon_parametre').Value := Edit1.Text;
    ADOQuery.Open;
    while not ADOQuery.Eof do
      begin
      ListBox1.Items.Add(ADOQuery1.FieldByName('monchamps').AsString);
      ADOQuery1.Next;
      end;
    Il me semble nécessaire d'ajouter "ListBox1.Clear" afin de supprimer tous les items. Il est également possible d'améliorer le déroulement de "While" en créant un TField persistant. Ainsi, nous aurions :

    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
     
    procedure
    var
      lField: TField;
    begin
      ListBox1.clear; 
      ADOQuery1.SQL.Clear;
      ADOQuery1.SQL.Add('select * from matable where Champs = :mon_parametre');
      ADOQuery1.Parameters.ParamByName('mon_parametre').Value := Edit1.Text;
      ADOQuery.Open;
      lField := ADOQuery1.FieldByName('monchamps');
      while not ADOQuery.Eof do
      begin
         ListBox1.Items.Add(lField.AsString);
         ADOQuery1.Next;
      end;
    A tester afin de mesurer les résultats

  5. #5
    Membre expert
    Avatar de Barbibulle
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    2 048
    Détails du profil
    Informations personnelles :
    Âge : 54
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 2 048
    Points : 3 342
    Points
    3 342
    Par défaut
    Difficile de répondre d'autant que ce n'est pas le code d'origine, car celui donné ne peut pas fonctionner.

    Utilisation d'une requête paramétrée ADOQuery1 puis ouverture d'une autre ADOQuery et une boucle while mixant ADOQuery et ADOQuery1.

    Le Tfield c'est bien mais ce n'est pas ça qui explique un temps si long.

    1 seconde pour une simple recherche sur un champ d'une table de 8000 enregistrement c'est déjà extrêmement long.

    Quelle est la base de données ?

    Base locale ou distante ? (si distante, en réseau local ou via internet ?)

    Testez votre requête avec requêteur souvant il y en a un de fournis avec le SGBD ainsi que des outils d'analyse.

  6. #6
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 043
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 67
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 043
    Points : 40 957
    Points
    40 957
    Billets dans le blog
    62
    Par défaut
    Citation Envoyé par idaram Voir le message
    j'utilise le composant ADOQuery et je voie pas de "prepare" dedans
    il n'y a pas d'instruction prepare effectivement mains une propriété prepared qu'il suffit de mettre à true au runtime et ce après construction de la requête
    MVP Embarcadero
    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
    SGBD : Firebird 2.5, 3, SQLite
    générateurs États : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd

  7. #7
    Membre expert
    Avatar de Barbibulle
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    2 048
    Détails du profil
    Informations personnelles :
    Âge : 54
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 2 048
    Points : 3 342
    Points
    3 342
    Par défaut
    Le "prepare" qu'il soit fait ou non n'est à mon avis pas le problème.

    Une table de seulement 8000 enregistrements et 1000 ms à 20000 ms de temps de réponse pour une simple requête !

    Pour comparaison j'ai créé une table sur firebird de 8000 enregistrements. Une colonne textelong varchar(2000) rempli avec des chaines random et non indexé.

    Une requête utilisant LIKE '%to%' sur cette colonne ne met que 125ms (la requête oblige le balayage complet de la table).

    Sans prépare sans rien.

    Ici on parle d'une requête simple avec un seul critère d'égalité stricte sur un champ qui serait 10 à 200 fois plus lente...

    On n'est pas dans de l'optimisation fin.

    Autre question : La connexion à la base de données est faite quand ? à l'ouverture du logiciel ou c'est le Open du query qui entraîne la connexion ?

    Mais je persiste : Qu'il donne la vrai requête, les conditions d'environnement (reseau notamment) BDD etc.

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 459
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 459
    Points : 24 873
    Points
    24 873
    Par défaut
    idaram
    Quelle SGBD ?
    ACCESS ? SQL SERVER ? ORACLE ?
    ... plusieurs personnes ont posés la question, c'est important d'y répondre !

    Citation Envoyé par SergioMaster Voir le message
    1- essayer de faire un préparation de la requête (prepare)
    Entièrement d'accord, une requete préparée va allouer des ressources côté serveur, cela évite l'analyse à chaque ouverture
    Une requete lancée en boucle ou fréquemment dans une application, c'est très significatif

    Pour illustrer la propriété Prepared
    Il y a cette exemple dans la documentation

    En reprenant ton code
    Je te montre le Prepared mais dans le cas d'un SQL fourni par code de cette façon sans volonté de réutilisation, le gain sera nul.

    J'ai corrigé le mélange ADOQuery1 et ADOQuery, j'ai supposé que ce n'était qu'un code démonstratif
    De plus tu manipule une IHM, cela peut ralentir aussi
    Il existe le TDBGrid ou la TDBListBox qui évite de tout copier dans une liste

    Si ta TListBox contient la propriété Sorted à True, cela ralentira encore plus !
    Pour améliorer la mise à jour de la TListBox, il faut lui indiquer que l'on va la remplir
    BeginUpdate - début de la mise à jour, cela inhibe le dessin lors de l'ajout, un gain de temps énorme
    EndUpdate - provoque le dessin une fois le traitement de remplissage terminé

    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
     
    ListBox1.Items.BeginUpdate();
    try
      ListBox1.Items.Clear();
     
      ADOQuery1.Close();
     
      ADOQuery1.SQL.Text :='select * from matable where Champs = :mon_parametre';
      ADOQuery1.Prepared := True; // Ici cela peut prendre peut de temps
     
      ADOQuery1.Parameters.ParamByName('mon_parametre').Value := Edit1.Text;
      ADOQuery1.Open(); // temps plus court car déjà préparé
     
      while not ADOQuery1.Eof do
      begin
        ListBox1.Items.Add(ADOQuery1.FieldByName('monchamps').AsString);
        ADOQuery1.Next();
      end;
     
    finally
      ListBox1.Items.EndUpdate();
    end;


    Citation Envoyé par SergioMaster Voir le message
    2- s'assurer que le champ soit indexé
    Une autre excellente remarque !
    J'ai eu la surprise qu'en ORACLE, cela ne génère pas un index automatiquement pour un champ déclaré en Foreign Key
    J'avais exactement le même comportement, cela passait de 50ms à plusieurs secondes, presque la minute !
    Des temps totalement extrème, la requete ne renvoyait que 10 à 500 enregistrements
    Ce qui penait était une jointure entre deux tables mais cela a commencé à se remarquer qu'au bout de 1 000 000 enregistrements
    Maintenant, c'est plus de 3millions, et grace à l'index, c'est stable entre 50ms et 150ms


    Comme le souligne Barbibulle, un temps aussi long pour une table si petite, c'est totalement anormal !
    C'est comme si tu avais un lock

    Tu testes seul sur ta base ?
    si oui, normalement pas de lock, si non, c'est tes collègues qui pertubent tes tests, pire, j'espère que ce n'est pas directement sur une base en PROD

    On ne peut rien dire de plus sans connaitre le SGDB !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Mars 2003
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2003
    Messages : 356
    Points : 133
    Points
    133
    Par défaut
    si tu mets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ListBox1.Items.Add(ADOQuery1.FieldByName('monchamps').AsString);
    en commentaire avec a la place

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     toto:= ADOQuery1.FieldByName('monchamps').AsString;
    juste pour voir si c'est pas uniquement la listbox qui fait varier le temps

Discussions similaires

  1. limiter la recherche dans une requete
    Par adiltyane dans le forum SQL
    Réponses: 2
    Dernier message: 25/12/2007, 16h41
  2. recherche dans une requete
    Par Willygramme dans le forum VBA Access
    Réponses: 2
    Dernier message: 21/08/2007, 14h28
  3. Réponses: 2
    Dernier message: 27/05/2007, 13h26
  4. Réponses: 3
    Dernier message: 08/03/2007, 11h45
  5. à la recherche d'une requete sql
    Par medmen dans le forum Langage SQL
    Réponses: 1
    Dernier message: 09/08/2006, 14h18

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