← Retourner à la page principale



Optimisations en WLangage® *

* Les marques "PC SOFT®" et "WINDEV®" sont déposées par la société PC SOFT®.

Faire des ajouts en masse dans un fichier de données
Faire une recherche d'un enregistrement dans une boucle


Effectuer des ajouts en masse dans un fichier de données

Avec la fonction HAjoute()

L'ajout d'un enregistrement dans un fichier de données s'effectue avec la fonction HAjoute() lien externe.
Voici un exemple de code simple qui fonctionne :

POUR i = 1 _À_ 65535 
    HRAZ(SOCIETE) 
    SOCIETE.Nom = "Société "+i 
    HAjoute(SOCIETE) 
FIN

La fonction HAjoute() est idéale pour des ajouts ponctuels, c'est-à-dire une dizaine d'ajout à la suite. Dès lors que l'on souhaite effectuer des ajouts en masse. Cette solution s'avère relativement lente.

Avec les fonctions HEcrit() et HRéindexe()

Une première optimisation est d'utilisation la fonction HEcrit() lien externe.
Voici un exemple de code simple qui fonctionne :

POUR i = 1 _À_ 65535 
    HRAZ(SOCIETE) 
    SOCIETE.Nom = "Société "+i 
    HEcrit(SOCIETE, HNbEnr(SOCIETE)+1) 
FIN
HRéindexe(SOCIETE)

La combinaison des fonctions HEcrit() + HRéindexe() permet d'optimiser les ajouts en masse. Effectivement après chaque appel à la fonction HAjoute() une réindexation du fichier de données est effectuée. Donc le fait d'effectuer une réindexation à la toute fin permet de gagner du temps de traitement.

Avec la commande "INSERT INTO" multiple

Cependant une solution plus rapide existe : construire une requête SQL d'ajout multiple directement avec la commande "INSERT INTO".
Voici un exemple de code simple qui fonctionne :

sReqInsert 	est une chaîne = "INSERT INTO SOCIETE (Nom) VALUES " 
sReqValues 	est une chaîne 
sReqValue 		est une chaîne = "('%1')" 

POUR i = 1 _À_ 65535 
    sReqValues += [","]+ ChaîneConstruit(sReqValue, "Société "+i) 
FIN 

sReqComplete est une chaîne = sReqInsert + sReqValues 
sdInsert est une Source de Données 
HExécuteRequêteSQL(sdInsert, hRequêteDéfaut, sReqComplete) 

J'attire votre attention sur plusieurs points critiques avec cette méthode :
1) Le fait d'utiliser la fonction ChaîneConstruit() avec une requête SQL en dur n'est pas recommandée. En effet, cela ouvre à des failles de sécurité (par exemple : l'injection SQL).
2) Une taille excessive d'une requête SQL peut provoquer une exception WLangage® provoquée par la saturation mémoire du système.



Effectuer une recherche d'un enregistrement dans une boucle

Avec la fonction HLitRecherchePremier() dans une boucle

Voici un exemple de code non optimisé :

sPersonnelNom, sPersonnelPrenom, sSocieteNom est une chaîne 
POUR TOUT PERSONNEL 
    (sPersonnelNom, sPersonnelPrenom, sSocieteNom) = (PERSONNEL.Nom, PERSONNEL.Prenom, "") 
    SI HLitRecherchePremier(SOCIETE, IDSOCIETE, PERSONNEL.IDSOCIETE) ALORS 
        sSocieteNom = SOCIETE.Nom 
    FIN 
    // ... Traitement avec les 3 chaînes ... 
FIN 

Pour chaque enregistrement du fichier de données PERSONNEL, une recherche sur la SOCIETE est effectuée. C'est-à-dire que toutes les rubriques du fichier de données PERSONNEL sont lues puis un enregistrement dans le fichier de données SOCIETE est lu et ses variables HFSQL sont mises à jour.

Avec un tableau associatif

Une première optimisation peut être réalisée sur la recherche dans le fichier de données SOCIETE. Effectivement il est inutile d'effectuer une recherche sur une SOCIETE déjà lue.
Une deuxième optimisation peut être réalisée avec l'utilisation du mot clé SANSSAUVEPOSITION.
Voici un exemple de code simple qui fonctionne :

taSociete est un tableau associatif (*,*,wlEntier_8) de chaîne 
sPersonnelNom, sPersonnelPrenom, sSocieteNom est une chaîne 
POUR TOUT PERSONNEL SANSSAUVEPOSITION 
    (sPersonnelNom, sPersonnelPrenom, sSocieteNom) = (PERSONNEL.Nom, PERSONNEL.Prenom, "") 
    SI taSociete[PERSONNEL.IDSOCIETE]..Vide ALORS 
        taSociete[PERSONNEL.IDSOCIETE] = HLitRecherchePremier(SOCIETE, IDSOCIETE, PERSONNEL.IDSOCIETE) ? SOCIETE.Nom sinon "" 
    FIN 
    sSocieteNom = taSociete[PERSONNEL.IDSOCIETE] 
    // ... Traitement avec les 3 chaînes ... 
FIN 

Avec une requête SQL

La meilleure solution est de tout faire dans une requête SQL. Ainsi seules les rubriques réellement souhaitées sont récupérées. Et il y a moins d'aller-retour entre l'applicaton et le serveur de base de données.
Voici un exemple de code simple qui fonctionne :

sPersonnelNom, sPersonnelPrenom, sSocieteNom est une chaîne 
reqPersonnel est une Requête SQL = 
[ 
    SELECT PERSONNEL.Nom AS P_Nom, PERSONNEL.Prenom AS P_Prenom, SOCIETE.Nom AS S_Nom 
    FROM PERSONNEL 
    LEFT JOIN SOCIETE ON SOCIETE.IDSOCIETE = PERSONNEL.IDPERSONNEL 
    ORDER BY SOCIETE.Nom, PERSONNEL.Nom, PERSONNEL.Prenom 
] 
SI HExécuteRequête(reqPersonnel) _ET_ (HNbEnr(reqPersonnel) > 0) ALORS 
    POUR TOUT reqPersonnel SANSSAUVEPOSITION 
        (sPersonnelNom, sPersonnelPrenom, sSocieteNom) = (reqPersonnel.P_Nom, reqPersonnel.P_Prenom, reqPersonnel.S_Nom) 
        // ... Traitement avec les 3 chaînes ... 
    FIN 
FIN 
HAnnuleDéclaration(reqPersonnel) 

La jointure "LEFT JOIN" permet de récupérer tout le personnel même ceux qui ne sont dans aucune société.
Il est important d'utiliser les fonctions HAnnuleDéclaration() ou HLibèreRequête() afin de libérer les ressources au plus tôt.
Une autre optimisation peut être réalisée en utilisant la fonction "TOP" qui permet de ne récupérer que les X premiers enregistrements s'il est inutile d'en récupérer beaucoup.