VBA optimiser vitesse d'exécution macro
Résolu
Bonjour,
tout d'abord, je sais que excel n'est pas initialement conçu pour de la gestion de bdd, et que MySQL ou Access seraient plus adaptés mais je n'ai pas le choix des armes pour cette bataille.
je codé un macro dans le but suivant :
je dispose d'un classeur "détail" qui contient le détail simplifié des facturations d'un magasin, soit 1 ligne par article avec :
colonne 1 : le numéro d'article
colonne 2 : le numéro de facture
colonne 3 : la vendue
colonne 4 : la date de vente
le but de la macro est de créer une nouvelle ligne pour chaque article et d'y reporter :
colonne 1 : le numéro d'article
colonne 2 : le total des mouvements de stock
colonne 3 : la dernière date de vente
Là où Excel patine à mort, c'est pour la colonne "total des mouvements de stock".
A savoir pour mieux comprendre :
la macro affronte au minimum 30 000 lignes (si si)
le classeur a préalablement été mis en forme de la manière suivante :
- les articles sont triés par ordre croissant
- pour chaque article, la première ligne correspond toujours à la ligne où le total doit être reporté.
En résumé, la macro :
- repère la première occurence pour chaque article
- repère la plage contenant les mouvements de stock de l'article repéré
- calcule le total de cette plage
- efface les lignes devenues obsolètes
(1) : sort de la boucle avant LigMax car la suppression de ligne raccourcit le tableau
(2) : les cellule devant contenir le total sont les seules à être vides, je les repère donc ainsi
(3) : la plage de calcule est donc (x1 ; x2)
(4) : j'anticipe les plages d'une seul ligne sinon -> erreur sur la méthode range à venir
(5) : supression des lignes en temps réel pour alléger le classeur et donc libérer de la ressource : résultat constaté
Comme vous le voyez, j'ai déjà :
- isolé la boucle fatidique dans une sub (si je la laisse dans la macro de départ c'est le plantage assuré)
- inhibé le recalcul automatique du classeur (encore qu'il ne contient aucune formule... mais au cas où...)
- figé la fenêtre excel pour limiter la perte de ressource.
Malgré cela, la macro ne traite que 2 à 3 lignes par seconde au début, et comme je supprime des données au fur et à mesure, la excel pédale de moins en moins et arrive à étaler 10 à 15 lignes par seconde vers la fin (oui oui j'ai tout calculé...)
Je suis donc à la recherche d'autre moyens d'acélérer lexécution de cette boucle.
Merci de vos conseils car cette boucle n'est qu'une petite partie d'un programme qui lui même est répété 10 fois (car 10 magasins à traiter) et d'après mes estimations, cela porterait la durée total des traitements à entre 3 et 5 heures... !!!
tout d'abord, je sais que excel n'est pas initialement conçu pour de la gestion de bdd, et que MySQL ou Access seraient plus adaptés mais je n'ai pas le choix des armes pour cette bataille.
je codé un macro dans le but suivant :
je dispose d'un classeur "détail" qui contient le détail simplifié des facturations d'un magasin, soit 1 ligne par article avec :
colonne 1 : le numéro d'article
colonne 2 : le numéro de facture
colonne 3 : la vendue
colonne 4 : la date de vente
le but de la macro est de créer une nouvelle ligne pour chaque article et d'y reporter :
colonne 1 : le numéro d'article
colonne 2 : le total des mouvements de stock
colonne 3 : la dernière date de vente
Là où Excel patine à mort, c'est pour la colonne "total des mouvements de stock".
A savoir pour mieux comprendre :
la macro affronte au minimum 30 000 lignes (si si)
le classeur a préalablement été mis en forme de la manière suivante :
- les articles sont triés par ordre croissant
- pour chaque article, la première ligne correspond toujours à la ligne où le total doit être reporté.
En résumé, la macro :
- repère la première occurence pour chaque article
- repère la plage contenant les mouvements de stock de l'article repéré
- calcule le total de cette plage
- efface les lignes devenues obsolètes
Sub B_Compil_Dernvte()
Dim x, x1, x2, z, LigMax As Long
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
[...]
For x = 1 To LigMax
If Not Cells(x, 1) <> "" Then Exit For ' (1)
If Cells(x, 2) = "" Then ' (2)
x1 = x + 1
For z = x1 To LigMax
If Cells(z, 1) = Cells(x, 1) Then x2 = z
Next z (3)
If x1 = x2 Then ' (4)
Cells(x, 2) = Cells(x + 1, 2)
Else: Cells(x, 2).Value = WorksheetFunction.Sum(Range(Cells(x1, 2).Address & ":" & Cells(x2, 2).Address))
End If
Range(Cells(x1, 1), Cells(x2, 1)).EntireRow.Delete ' (5)
End If
Next x
[...]
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Application.Calculation = xlCalculationAutomatic
ActiveWorkbook.Save
End Sub
(1) : sort de la boucle avant LigMax car la suppression de ligne raccourcit le tableau
(2) : les cellule devant contenir le total sont les seules à être vides, je les repère donc ainsi
(3) : la plage de calcule est donc (x1 ; x2)
(4) : j'anticipe les plages d'une seul ligne sinon -> erreur sur la méthode range à venir
(5) : supression des lignes en temps réel pour alléger le classeur et donc libérer de la ressource : résultat constaté
Comme vous le voyez, j'ai déjà :
- isolé la boucle fatidique dans une sub (si je la laisse dans la macro de départ c'est le plantage assuré)
- inhibé le recalcul automatique du classeur (encore qu'il ne contient aucune formule... mais au cas où...)
- figé la fenêtre excel pour limiter la perte de ressource.
Malgré cela, la macro ne traite que 2 à 3 lignes par seconde au début, et comme je supprime des données au fur et à mesure, la excel pédale de moins en moins et arrive à étaler 10 à 15 lignes par seconde vers la fin (oui oui j'ai tout calculé...)
Je suis donc à la recherche d'autre moyens d'acélérer lexécution de cette boucle.
Merci de vos conseils car cette boucle n'est qu'une petite partie d'un programme qui lui même est répété 10 fois (car 10 magasins à traiter) et d'après mes estimations, cela porterait la durée total des traitements à entre 3 et 5 heures... !!!
7 réponses
-
Contributeur0,0625 secondes pour 10000 lignes
https://www.cjoint.com/?3AfjCKxYaHA
avec 512 Mo RAM DDR et 3 ghz proc
j'ai considéré que la dernière date était celle de la 1° ligne d'une ref
La restitution se fait à coté pour vérification (essais) à modifier enn définitif ( voir macro)
Tu dis...
Pour les tutos:
https://silkyroad.developpez.com/
Michel-
ContributeurBonjour Michel, +1
Phoenellion >> Pas de panique, ça fonctionne impec, change juste la ligne de place
Application.ScreenUpdating = False' provisoire pour essai de rapidité MsgBox "durée: " & (Timer - Start) & " sec." 'provisoire pour essai de rapidité
Pour avoir..MsgBox "durée: " & (Timer - Start) & " sec." 'provisoire pour essai de rapidité Application.ScreenUpdating = True ' provisoire pour essai de rapidité
Michel voulais prolonger le suspense :-))
A+ -
-
Bonjour à vous,
merci pour ton code Michel, et pour ta participation Lermite. J'ai passé une bonne heure à tout déchiffrer mais ce fut très instructif, et pas seulement sur les variables tableaux.
Maintenant, il faut réutiliser tout ça comme il faut...
J'attire juste votre attention sur mon post un peu plus bas concernant l'instruction lookup qui est ma seconde source de ralentissement... -
ContributeurBonjour
je ne vois pas l'intérêt ,dans ce cas, d'écrire des formules avec VBA: autant écrire la formule à la main et double cliquer sur la poignée d'implémentation....
écrire des formules à la place d'une affectation coute un poids supplémentaire de 20% du classeur
n'oublie pas que tu es sur 30 000 lignes et que dans les grandes listes (nbre lignes * nbre de colonnes) les réflexes "je raisonne par formules" est mauvais...
mais c'est ton projet, donc tu fais ce que tu veux
maintenant si les calculs sont simples et le classeur pas trop lourd, une formule recopiée peut ^tre rapide : voir cette petite démo "éviter copy-past"
https://www.cjoint.com/?3AgjGR2NgLV -
A ne pas oublier qu'on ne parle ici que d'une petite partie du tout.
Au total il y a 5 tables (volumineuses) par magasin à compiler en une seule, ce pour 10 magasins, et le tout 2 fois par mois.
Je comprends ce que tu veux dire mais j'y suis tout de même obligé, si je dois écrire les formules à la main. Ce programme perd tout son sens.
Cela dit, je pense comprendre ton raisonnement en j'essaierai de m'en rapprocher dans la mesure du possible en évitant de faire une boucle et préférer une formule puis l'implémenter et je pense que ta démo va encore m'en apprendre pas mal ^^
Un GRAND merci pour votre aide et votre patience.
Et bien que je n'y ai pas pensé plus tôt : Meilleurs Voeux pour cette nouvelle année !
-