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

Lazarus Pascal Discussion :

TMemDataSet vs TSQLQuery [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut TMemDataSet vs TSQLQuery
    Bonjour à tous,
    J'utilise Lazarus pour un projet personnel de création dynamique de formulaires (+ de 400 formulaires) avec gestion des accès concurrentiels.

    Les formulaires comprennent :
    * une grille lecture seule de 50 à 100 enregistrements (lazy loading) comprenant max 5 colonnes. La requête SQL n'informe que les 5 champs.
    * des onglets et panels comprenant les restant des champs (+/- 100 champs TEdit) à afficher au fur et à mesure du parcours de la grille gauche. La requete SQL informe tous les champs (select *) concernant l'enregistrement en cours de la grille (where RowID = GrilleCrurrentID).

    Je souhaite savoir quelle méthode est la plus intéressante/efficace/maintenable pour la lecture et l'affichage de données provenant d'une base PostgreSQL :
    1- TSQLQuery + TDataSource avec remplissage auto de TDBGrid + TDBEdit + TDBText
    2- TSQLQuery avec remplissage manuel de composants TStrinGrid et TEdit
    3- TSQLQuery puis CopyFromDataset vers un composant TMemDataSet avec remplissage auto des composants TDBGrid + TDBEdit + TDBText


    J'ai constaté de la lenteur avec la première méthode. La seconde demande pas mal de travail. Pour la troisième, beaucoup de posts parlent de la vitesse avantageuse de TMemDataSet. J'y vois également l'avantage de pouvoir utiliser des composants connectés.

    Merci de me faire profiter de vos lumières.

    Salim.

  2. #2
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    avril 2002
    Messages
    1 782
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : avril 2002
    Messages : 1 782
    Points : 5 907
    Points
    5 907
    Par défaut
    Bonjour,
    Citation Envoyé par larsal007 Voir le message
    J'utilise Lazarus pour un projet personnel de création dynamique de formulaires (+ de 400 formulaires) avec gestion des accès concurrentiels.
    via les transactions de PostGres ?

    Citation Envoyé par larsal007 Voir le message
    * une grille lecture seule de 50 à 100 enregistrements (lazy loading) comprenant max 5 colonnes. La requête SQL n'informe que les 5 champs.
    Une requête "mono table" de 50 à 100 lignes, 5 colonnes ?
    Soit un volume de données compris entre 2 et 20 Ko...

    Citation Envoyé par larsal007 Voir le message
    * des onglets et panels comprenant les restant des champs (+/- 100 champs TEdit) à afficher au fur et à mesure du parcours de la grille gauche. La requete SQL informe tous les champs (select *) concernant l'enregistrement en cours de la grille (where RowID = GrilleCrurrentID).
    Une requête multi tables (jointures) de 1 ligne, 100 colonnes ?
    Soit un volume de données d'environ 4 Ko...

    Le volume global de données n'est pas très important, mais :
    Citation Envoyé par larsal007 Voir le message
    J'ai constaté de la lenteur avec la première méthode.
    A quel moment précis ?
    • Lors de l'interrogation de la base de données ?
      Optimiser la base de données, ses index, et la requête SQL
      Découper la requête multi table renvoyant une seule ligne de 100 colonnes en plusieurs requêtes mono table (ou presque) renvoyant une seule ligne de quelques colonnes
      AMHA, ce 2° point me parait être la clé du problème.
    • Lors de l'alimentation des TDB* composants ?
      Découper la fiche avec plusieurs onglets et 100 champs en en plusieurs fiches et des requêtes associées.
    Philippe.

  3. #3
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par larsal007 Voir le message
    Je souhaite savoir quelle méthode est la plus intéressante/efficace/maintenable pour la lecture et l'affichage de données provenant d'une base PostgreSQL :
    1- TSQLQuery + TDataSource avec remplissage auto de TDBGrid + TDBEdit + TDBText
    2- TSQLQuery avec remplissage manuel de composants TStrinGrid et TEdit
    3- TSQLQuery puis CopyFromDataset vers un composant TMemDataSet avec remplissage auto des composants TDBGrid + TDBEdit + TDBText

    J'ai constaté de la lenteur avec la première méthode. La seconde demande pas mal de travail. Pour la troisième, beaucoup de posts parlent de la vitesse avantageuse de TMemDataSet. J'y vois également l'avantage de pouvoir utiliser des composants connectés.
    Bonjour,

    au risque de paraître tout à fait iconoclaste, j'ai retenu il y a longtemps la solution 2. Je ne le regrette pas. Comme c'est une chaîne directe basée uniquement sur 3 composants, le sqlConnect, le sqlQuery et la StringGrid on obtient une souplesse inégalée (y compris pour contourner de petits bugs ponctuels), une fluidité inégalée, une capacité de modification et de personnalisation également inégalée. L'inconvénient en effet est la programmation par exemple des tris et du multiselect. Un autre avantage est d'éviter l'effondrement de votre Form en cas de rupture de connexion... puisqu'une fois chargée la StringGrid est indépendante du sqlQuery... et vous pouvez continuer votre travail et, même si vous travaillez en Update/Insert dans une situation de rupture de connexion, rien n'empêche de stocker (facilement) en attendant la reconnexion ultérieure.

    C'est ce que je vous conseillerais s'il s'agit d'un investissement à long terme. Mais je le répète, c'est un choix peu répandu que je peux toutefois qualifier de fonctionnel pour l'avoir utilisé pendant plus de 3 ans sur des bases (mySQL d'abord puis pgSQL ensuite et enfin, un petit peu mariaDB) multi-utilisateurs distantes hébergées.

    Juste avant de quitter Lazarus, j'avais commencé à découvrir une autre possibilité. Je ne l'ai pas optimisée mais j'ai eu le temps de faire des maquettes fonctionnelles. Vous utilisez un sqlConnect+sqlQuery sur votre base pgSQL (RQ : le connecteurs natif et son DataSet sont remarquables : cette combinaison permet de faire remonter directement les N° d"erreur renvoyées par le serveur avec la nomenclature pgSQL). Parallèlement, vous déployez une chaîne habituelle sqlConnect-->dbGrid sur une base SQLite:memory:. Au lancement du programme, la base pgSQL remplit la base SQLite en mémoire. Vous utilisez alors votre chaîne SQLite en mémoire de manière instantanée en profitant des automatismes de celle-ci. On retrouve la fluidité. Pas d'effondrement une fois la table SQLite :memory: chargée. J'ai poussé le test avec la gestion en simultané et en décalé des requêtes Insert/Update/Delete sur les tables pgSQL. Cela fonctionne proprement.

    Cordialement. Gilles
    Dernière modification par Invité ; 14/06/2014 à 14h49. Motif: Relecture

  4. #4
    Membre du Club
    Homme Profil pro
    Inscrit en
    février 2009
    Messages
    34
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations forums :
    Inscription : février 2009
    Messages : 34
    Points : 55
    Points
    55
    Par défaut
    Bonjour à tous deux et merci de participer,
    @philippe :
    Citation Envoyé par Ph. B. Voir le message
    via les transactions de PostGres ?
    J'utilise le composant TSQLransaction. Est ce qu'l y a un autre moyen?

    Citation Envoyé par Ph. B. Voir le message
    A quel moment précis ?
    • Lors de l'interrogation de la base de données ?
      Optimiser la base de données, ses index, et la requête SQL
      Découper la requête multi table renvoyant une seule ligne de 100 colonnes en plusieurs requêtes mono table (ou presque) renvoyant une seule ligne de quelques colonnes
      AMHA, ce 2° point me parait être la clé du problème.
    • Lors de l'alimentation des TDB* composants ?
      Découper la fiche avec plusieurs onglets et 100 champs en en plusieurs fiches et des requêtes associées.
    La lenteur vient lors d'une connexion distante mais cela reste acceptable (4 à 5 secondes). Par contre, je vais appliquer les points 2 et 3 pour réduire au maximum la taille des paquets et fluidifier la navigation . Merci pour tes suggestions.

    @Gilles:
    Je te remercie pour ton argumentation. Je suis tout à fait d'accord avec toi, la solution d'une chaîne directe sqlconnect+sqlquery+stringgrid a aussi ma préférence. Elle demande plus de code mais cela est gérable en automatisant un max. Cela apporte énormément de souplesse et de possibilités en terme de fluidité et de continuité en cas de rupture de connexion.
    Concernant la solution SQLite:Memory, je pense que l'option 3 avec l'usage de TMemDataSet est équivalente puisque les données sont également stockées en mémoire (MemDataSet.CopyFromDataset(SQLQuery)) et peuvent être enregistrées dans sur Disque Dur pour un update ultérieur. Par contre je ne connais pas la différence de performance entre les deux solutions (sqlite <> memdataset). Je pencherais pour sqlite etant donné que c'est une base de données en mémoire mais cela en vaut il la peine s'il faut faire une copie de la base postgres vers sqlite à chaque lancement de l'application.

    Citation Envoyé par selzig Voir le message
    RQ : le connecteurs natif et son DataSet sont remarquables : cette combinaison permet de faire remonter directement les N° d"erreur renvoyées par le serveur avec la nomenclature pgSQ
    Comment faire pour récupérer le n° d'erreur? Je souhaite le confronter à une liste de codes d'erreurs pour personnaliser et franciser les messages IHM.

    Merci encore une fois à tous les deux.
    Salim.

  5. #5
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    l'avantage de l'utilisation de SQLite est que pour les insert, update et delete, les requêtes sont identiques en pgSQL et SQLite... Donc sur la base pgSQL, j'effectuais les blocages si nécessaires et des transactions systématiquement et à ce titre, j'avais besoin de différencier les codes d'erreurs proprement... Si Commit, idem "allégé" sur SQLite ... Si Rollback, message d'erreur (avec la nomenclature pgSQL) et on ne touche pas au DataSet SQLite... De plus, on peut lancer les méthodes afférentes à pgSQL à partir de la chaîne SQLite de son dbNavigateur par exemple... C'est plutôt facile à automatiser....

    En réalité, j'ai développé cette approche SQLite:memory: pour Windev, et curieux, j'ai voulu voir si elle était transposable en Lazarus... Elle l'est...

    Pour le pgSQL, c'est une des rares fois où l'équipe Lazarus a bien voulu donner suite à l'une de mes demandes, et qui plus est, dans un temps raisonnable. Un peu de lecture : http://www.developpez.net/forums/d12...e-error-codes/ (pour les Code Error des TPQConnection) et http://www.developpez.net/forums/d12...-pqconnection/ (cela date un peu...)

    Pour le code lui-même, je regarde... enfin NotePad++ est en train de fouiller dans mes archives.rar... Cela risque d'être un peu long...

    Cordialement. Gilles

    Addendum 18:33 NotePad++ a fait correctement son travail.
    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
    procedure TFormMain.Button10Click(Sender: TObject);
    var strm: TStream;
      Result : boolean;
    begin
      strm:=TMemoryStream.Create;
      imgSrc.Picture.SaveToStream(strm);
      with pgQueryUID do try
         if not DataBase.Connected then DataBase.Connected := True;
         Close;
         TSQLTransaction(pgQueryUID.Transaction).StartTransaction;
         with SQL, Params do begin
           Clear;
           SQL.Text := 'INSERT INTO test2012 '+
                       '(teid, tenom, teblob) '+
                       'VALUES ' +
                       '(:paID, :paNOM, :paIMAGE );';
           ParamByName('paID').AsString  := AleaString();
           ParamByName('paNOM').AsString := 'TEST numéro 6';
           ParamByName('paIMAGE').SetBlobData(Strm, Strm.Size);
         end;
         ExecSQL;
         Close;
         TSQLTransaction(pgQueryUID.Transaction).Commit;
         Result := True;
       except
         on E: EPQDatabaseError do
           begin
              TSQLTransaction(pgQueryUID.Transaction).Rollback;
             Showmessage('Database error: '+
             'Severity:           '+E.Severity + LineEnding +
             'SQLSTATE:           '+E.SQLSTATE + LineEnding +
             'Primary mesage:     '+E.MESSAGE_PRIMARY + LineEnding +
             'Detailed message:   '+E.MESSAGE_DETAIL + LineEnding +
             'Message hint:       '+E.MESSAGE_HINT + LineEnding +
             'Statement position: '+E.STATEMENT_POSITION);
     
             Result := False;
           end;
        on Z: Exception do
           begin
             // Assume it's an executable query.
             // A query containing a syntax error etc will be wrongly detected as executable
             // todo: fix this based on detailed error message retrieved from db!?!?
             showmessage('Exception : '+Z.ClassName+'/'+Z.Message);
           end;
       end;
        strm.Free;
     end;
    J'ai retrouvé l'exe mais je n'ai pas pu compiler le code. Sur le Lazarus qu'il me reste, mes anciens composants ne sont pas installés donc le chargement des .lpi est problématique (i.e. incomplet)... Pour convertir mes anciens codes, je n'ai besoin de lire que les .pas et mes .inc.



    A priori rien de particulier dans les uses... Bonne continuation.
    Dernière modification par Invité ; 14/06/2014 à 20h19. Motif: Relecture

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

Discussions similaires

  1. TsqlQuery et récupération de valeur générée
    Par Lucien dans le forum Bases de données
    Réponses: 2
    Dernier message: 19/10/2005, 15h44
  2. TSQLQuery et recordcount
    Par Cybher dans le forum C++Builder
    Réponses: 5
    Dernier message: 30/08/2005, 10h51
  3. problème avec le composant TSQLQuery
    Par vbcasimir dans le forum Bases de données
    Réponses: 6
    Dernier message: 31/05/2005, 17h45
  4. [TSqlQuery+dbexpress] Pbs Insertion
    Par fred64 dans le forum Bases de données
    Réponses: 2
    Dernier message: 11/05/2004, 14h07
  5. [DEBUTANT] TSqlQuery & requête simple
    Par fred64 dans le forum Bases de données
    Réponses: 3
    Dernier message: 21/04/2004, 12h35

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