PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV (précédentes versions) → MVP - lenteur récupération des donées
MVP - lenteur récupération des donées
Débuté par Eric D, 09 déc. 2016 15:18 - 7 réponses
Posté le 09 décembre 2016 - 15:18
Bonjour,

je développe un petit ERP avec windev 20, relié à un base HFSQl Client/Serveur d'environ 750 mo, en utilisant le design pattern MVP.

Je me suis appuyées sur l'exemple fournit par PCSoft : "Découverte MVP - Partie 2" pour mon développement. Ainsi mes classe models sont mappées à leur table respective et elles héritent d'une classe Base s'occupant de l’enregistrement et de la récupération des données avec les fonctions FichierVersMémoire() et MémoireVersFichier().

Malgré ce principe d'accès aux données qui me semble correcte, la récupération est très longue.

Est-ce que l'un d'entre vous a déjà eu un problème de ce genre avec ce principe ou avec le MVP ?
Est-ce que ça peut-être HFSQL ou mon serveur qui ne sont pas assez puissant ?

Merci de vos retours.
Cordialement
Posté le 09 décembre 2016 - 19:48
Bonjour

je n'utilise pas ce modèle, mais je peux te dire que le problème ne
vient pas de la base.

Le simple fait que tu nous dise que "...la récupération est très
longue..." sans autre précisions montre que tu ne maitrise pas la
logique d'accès à une base de données. MVP ou pas n'a rien à y voir non
plus.

Quelle récupération ?
Sur une requête ?
Sur un code particulier ?
Pour remplir une table ?
C'est combien "très longue" ?
Pour combien d'enreg ?

Cordialement


--
Fabrice Harari
Consultant WinDev, WebDev et WinDev Mobile International

A votre disposition : WXShowroom.com, WXReplication (open source) et
maintenant WXEDM (open source)

Plus d'information sur http://fabriceharari.com




Le 12/9/2016 à 9:18 AM, Eric D a écrit :
Bonjour,

je développe un petit ERP avec windev 20, relié à un base HFSQl
Client/Serveur d'environ 750 mo, en utilisant le design pattern MVP.

Je me suis appuyées sur l'exemple fournit par PCSoft : "Découverte MVP
- Partie 2" pour mon développement. Ainsi mes classe models sont mappées
à leur table respective et elles héritent d'une classe Base s'occupant
de l’enregistrement et de la récupération des données avec les fonctions
FichierVersMémoire() et MémoireVersFichier().

Malgré ce principe d'accès aux données qui me semble correcte, la
récupération est très longue.

Est-ce que l'un d'entre vous a déjà eu un problème de ce genre avec ce
principe ou avec le MVP ?
Est-ce que ça peut-être HFSQL ou mon serveur qui ne sont pas assez
puissant ?

Merci de vos retours.
Cordialement
Posté le 12 décembre 2016 - 11:12
Bonjour,

merci de votre retour.

Je l'admets l'explication n'est pas claire.

Je suis en train de créer une fenêtre avec un tableau, ou l'on peut ajouter / modifier / supprimer une ligne (classique).
Les données sont récupérées grâce à une boucle "POUR TOUT <nom de la table>" ou grâce aux fonctions "HLit...". Chaque enregistrement lu crée un objet qui est remplit grâce à la fonction "FichierVersMémoire()" (Les attributs de mes classes étant mappés à leurs attributs de la base), et qui fait la même chose pour les classes associées.

Ainsi mon tableau affiche environ 7000 lignes en 2 minutes. Les données sont pris sur 7 tables différentes, ou l'on prend au plus 7000 enregistrements sur chacune, pour un poids théorique de 18 mo.

Je précise que je débute en WinDev et que c'est la première fois que je développe avec une base ayant plusieurs millier d'enregistrements (Où sont les cas d'école avec une dizaine d’enregistrements ???)

Cordialement.
Posté le 12 décembre 2016 - 13:52
Bonjour

ce n'est pas un problème lié à windev, c'est un problème de conception
de l'appli.

D'abord, afficher une table avec 7000 lignes dedans, en 30 ans de
développement, je n'ai JAMAIS vu un cas ou c'était nécessaire ou utile.

PERSONNE ne va lire 7000 lignes.

Donc, il faut afficher une table vide, avec des champs de
recherche/sélection au dessus, et n'afficher que ce que l'utilisateur
veut vraiment voir...

Ensuite, pour ce genre de chose, il faut privilégier des requêtes pour
limiter le nombre de transferts par le réseau.

Enfin, il faut bloquer l'affichage (..affichageactif, de mémoire)
pendant le remplissage de la table et le réactiver une fois qu'elle est
pleine.

Quand à dire que c'est très lent, relativisons : tu nous dis que tu lis
et affiche 49 000 enregs au total (7000*7), en 120 secondes. Ca fait pas
loin de 410 enregs lus par seconde. C'est loin d'être lent. Ca peut être
optimisé grace aux méthodes décrites au dessus, mais c'est loin d'être
lent vu les méthodes utilisées pour l'instant.

Cordialement


--
Fabrice Harari
Consultant WinDev, WebDev et WinDev Mobile International

A votre disposition : WXShowroom.com, WXReplication (open source) et
maintenant WXEDM (open source)

Plus d'information sur http://fabriceharari.com



Le 12/12/2016 à 5:12 AM, Eric D a écrit :
Bonjour,

merci de votre retour.

Je l'admets l'explication n'est pas claire.

Je suis en train de créer une fenêtre avec un tableau, ou l'on peut
ajouter / modifier / supprimer une ligne (classique).
Les données sont récupérées grâce à une boucle "POUR TOUT <nom de la
table>" ou grâce aux fonctions "HLit...". Chaque enregistrement lu crée
un objet qui est remplit grâce à la fonction "FichierVersMémoire()" (Les
attributs de mes classes étant mappés à leurs attributs de la base), et
qui fait la même chose pour les classes associées.

Ainsi mon tableau affiche environ 7000 lignes en 2 minutes. Les données
sont pris sur 7 tables différentes, ou l'on prend au plus 7000
enregistrements sur chacune, pour un poids théorique de 18 mo.

Je précise que je débute en WinDev et que c'est la première fois que je
développe avec une base ayant plusieurs millier d'enregistrements (Où
sont les cas d'école avec une dizaine d’enregistrements ???)

Cordialement.
Posté le 12 décembre 2016 - 16:46
Il y a un outil : l'analyseur de performance. En utilisant cet outil, tu sauras précisément combien de fois chaque fonction a été exécutée, combien de temps elle a pris etc etc, et tu pourras mieux cibler ton problème. Cet outil est essentiel en cas de problèmes de performance.

L'autre piste, c'est de passer par un hReIndexe()
Il faut lancer cette commande à intervalle réguliers. Un bon hReindexe() avec les bons paramètres, et les temps de réponse peuvent être divisés par 5 voire plus.
Membre enregistré
90 messages
Popularité : +7 (11 votes)
Posté le 13 décembre 2016 - 09:30
Fabrice Harari a écrit :
Bonjour

ce n'est pas un problème lié à windev, c'est un problème de conception
de l'appli.

D'abord, afficher une table avec 7000 lignes dedans, en 30 ans de
développement, je n'ai JAMAIS vu un cas ou c'était nécessaire ou utile.

PERSONNE ne va lire 7000 lignes.

Les lire, non. Mais sa table peut être utile ensuite pour de l'export, pour des stats ou que sais-je d'autres...
Ce n'est pas l'aider que de lui dire de ne pas faire ça.

déjà le ..affichageactif = faux avant le traitement devrait améliorer les choses.
Ensuite, passer par une requête.
Eviter aussi les traitements sur affichage d'une ligne...

Il y a peut-être des données qui peuvent être récupérées avant et stocker dans des tableaux de structure.
et donc éviter les accès base à ce moment là.

voir aussi les index.

Bref il y a plein de piste, mais sans code, ni même de contexte, difficile de t'aider.
Membre enregistré
2 messages
Posté le 13 décembre 2016 - 11:39
Merci pour vos conseils, je vais y regarder de plus près.

Le contexte étant que je souhaite afficher la liste des recoupes avec pour chacune sa cause avec sa famille, l'employé la demandant, le numéro du bon de fabrication et de la série, ainsi que l'article avec sa matière et sa couleur.

Pour le code, je suis en train de tous refaire, l'analyseur de Performance montre que ça ne viens pas de la base de données, mais je vous mets la classe Base, s'occupant de la récupération et de l'enregistrement des données.

// Classe modèle de base
Base est une Classe

nouveau est un booléen // Vrai si nouvelle instance du Modèle

PRIVÉE

id est un Variant

nomTable est une chaîne // Nom du fichier associé au modèle
nomClePrimaine est une chaîne // Nom de la rubrique clé unique du fichier
FIN

//---------------------------------------------------------------------------------------

Procedure Constructeur(snomTable, snomClePrimaine)

// initialisation des membres
nouveau=Vrai // nouvelle instance

nomTable=snomTable
nomClePrimaine=snomClePrimaine


//---------------------------------------------------------------------------------------

// Résumé : Permet d'ajouter ou modifier un objet dans sa base de donées
// Syntaxe :
//[ <Résultat> = ] Enregistrer (<lErreur> est CErreur)
//
// Paramètres :
// lErreur (CErreur) : Gère les erreurs
// Valeur de retour :
// booléen : // Aucune
//
Procedure Enregistrer(lErreur est une CErreur)

// en mode ajout
SI nouveau ALORS

// ajout de l'enregistrement
HRAZ(MonFichierMappé)
MémoireVersFichier(objet,MonFichierMappé)
HAjoute(MonFichierMappé)
SI ErreurDétectée() ALORS lErreur.Initialise(CErreur::ErreurHFSQL,HErreurInfo())

// Récupère l'identifiant à partir du fichier associé au modèle
id = {nomTable+"."+nomClePrimaine, indRubrique}

// récupération de la valeur de l'identifiant
FichierVersMémoire(objet,MonFichierMappé)

// instance existante
nouveau=Faux

// en mode modification
SINON
// positionnement dans le fichier
HLitRecherchePremier(MonFichierMappé,MaCléUniqueMappée,id)
SI HTrouve() ALORS
// modification
MémoireVersFichier(objet,MonFichierMappé)
HModifie(MonFichierMappé)
SI ErreurDétectée() ALORS lErreur.Initialise(CErreur::ErreurHFSQL,HErreurInfo())

// si l'enregistrement n'a pas été trouvé
SINON
// renseigne l'erreur
lErreur.Initialise(CErreur::NonTrouvé)
FIN
FIN

// ok
RENVOYER lErreur.ok

//---------------------------------------------------------------------------------------

// Résumé : <indiquez ici ce que fait la procédure>
// Syntaxe :
//[ <Résultat> = ] Supprimer (<lErreur> est CErreur)
//
// Paramètres :
// lErreur (CErreur) : <indiquez ici le rôle de lErreur>
// Valeur de retour :
// booléen : // Aucune
//
Procedure Supprimer(lErreur est un CErreur)

// en mode ajout, il n'y a rien à faire
SI nouveau ALORS RENVOYER Vrai

// positionnement dans le fichier
HLitRecherchePremier(MonFichierMappé,MaCléUniqueMappée,id)
SI HTrouve() ALORS
// suppression
HSupprime(MonFichierMappé)
SI ErreurDétectée() ALORS lErreur.Initialise(CErreur::ErreurHFSQL,HErreurInfo())

// si l'enregistrement n'a pas été trouvé
SINON
// renseigne l'erreur
lErreur.Initialise(CErreur::NonTrouvé)
FIN

// ok
RENVOYER lErreur.ok

//---------------------------------------------------------------------------------------

// Résumé : <indiquez ici ce que fait la procédure>
// Syntaxe :
//Charger ( [<source> est chaîne])
//
// Paramètres :
// source (chaîne ANSI - valeur par défaut="") : <indiquez ici le rôle de source>
// Valeur de retour :
// Aucune
//
Procedure Charger(Source est une chaîne = "")

// Il ne s'agit pas d'un nouvel élément
nouveau = Faux


// Si la source n'est pas renseignée
SI Source = "" ALORS

// Récupère l'identifiant à partir du fichier associé au modèle
id = {nomTable+"."+nomClePrimaine, indRubrique}

// Charge l'enregistrement en mémoire
FichierVersMémoire(objet,MonFichierMappé)

SINON

// Récupère l'identifiant à partir du fichier associé au modèle
id = {Source+"."+nomClePrimaine, indRubrique}

// Charge l'enregistrement en mémoire
FichierVersMémoire(objet,Source)

FIN


Ci-dessous le bout du MPD utiliser pour cette fenêtre.




Je précise que je reprends un ERP développé par une personne qui n’était pas un développeur, quelle avait déjà créer une fenêtre listant les recoupes comme voulus, où les données était toutes dans la même table (Je vous dis pas le nombre de doublons dans la base), et donc le tableau était relier à la table recoupe pour un affichage en quelques secondes.
Posté le 06 avril 2017 - 01:13
Coucou,

Utilse plutot "clé unique" que
// Récupère l'identifiant à partir du fichier associé au modèle
id = {Source+"."+nomClePrimaine, indRubrique}


MServer est une Classe, mapping=Server
hérite de MBase
PRIVÉE
// Member
m_n8ID est un entier sur 8 octets <mapping=IDServer, clé unique>
FIN


MBase est une Classe
// balbalbalbal
FIN

Procedure PUBLIQUE ID(): entier sur 8 octets
// Gestion des erreurs
ErreurChangeParamètre(epGotoCasErreur)
ExceptionChangeParamètre(epGotoCasException)
RENVOYER {"m_n8ID", indVariable}
CAS ERREUR:
ErreurPropage()
RENVOYER -1
CAS EXCEPTION:
ExceptionPropage()
RENVOYER -1


Charly