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

VBA Access Discussion :

Temps d'execution trop lent - Recordset DAO


Sujet :

VBA Access

  1. #1
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut Temps d'execution trop lent - Recordset DAO
    Bonjour,

    J'ai un souci de performance au niveau d'une base de données.
    En effet, je parcours une table (700 000 lignes) par le biais d'un recordset et en fonction de certaines conditions je mets à jour un ou plusieurs champs.

    Le problème et que cette opération prend énormèment de temps.

    Avez-vous une solution pour optimiser l'execution?

    Merci pour votre aide

    Voici un exemple de code que j'utilise :

    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
     
    Dim oRst as DAO.Recordset
    Dim oDb as DAO.Database
    Set oDb=CurrentDb
    Set oRst=oDb.OpenRecordset("TblCommande",dbOpenTable)
     
    While Not oRst.EOF
     
    '--------------------------
    Ici je mets des Conditions en fonction desquels un ou plusieurs champs de la table seront mis à jour
    '---------------------------
     
     
     
      'Passe en mode modification
      oRst.Edit
      'A  oRst.Fields("Champ9").Value=(Champ1 * champ2)^2/champ4
     
    'Mettre à Jour
      oRst.Update
      'Passe au suivant
      oRst.MoveNext
    Wend
     
    'Libération des objets
    oRst.Close
    oDb.Close
    Set oRst=Nothing
    Set oDb=Nothing

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonjour

    Au lieu de mettre ta table dans l'OpenRecordset, utilise une requête SQL qui comporte déjà les critères des conditions (clause Where).

    Ainsi ton recordset ne travaillera que sur ces lignes et non toute la table, cela devrait aller beaucoup plus vite.

    Philippe

  3. #3
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut
    Bonjour,

    Merci Philippe pour ton aide.

    Malheureusement, le problème de lenteur persiste.

    J'ai mis un exemple de code utilisé.

    En effet,

    TABLE_BRUTE : la table de départ qui contient toutes les informations nécessaires (700 000 lignes).
    ChpCritere : les critères (noms de champs de la TABLE_BRUTE)
    Le code s'execute normalement sans erreur mais la durée de traitement avoisine 3H ce qui constitue vraiment un handicap.

    Ma question, est ce possible d'optimiser le code ci-dessous? si oui comment?

    Si la démarche que j'ai suivie est fausse, merci de me faire part de vos suggestions.

    Merci


    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    Sub DB_TREAT(ByVal Path_BD As String, ByVal TABLE_BRUTE As String, _
                      ParamArray ChpCritere() As Variant)
     
     
     
    Dim DB As DAO.Database
    Dim Rst As DAO.Recordset
    Dim RstTMP As DAO.Recordset
    Dim intColIndex As Long
    Dim strSql As String
    Dim strSqlTMP As String
    Dim strWhere As String
    Dim strSelect As String
    'Dim strUpdate As String
    Dim v As Long
     
     
    Set DB = DAO.OpenDatabase(Path_BD, False, False)
     
    For v = LBound(ChpCritere) To UBound(ChpCritere)
        strSelect = strSelect & ChpCritere(v) & ", "
    Next v
     
    strSelect = Mid(strSelect, 1, Len(strSelect) - Len(", "))
     
    strSql = "SELECT DISTINCT " & strSelect & " FROM " & TABLE_BRUTE
     
    Set Rst = DB.OpenRecordset(strSql, DAO.dbOpenSnapshot)
     
     
     With Rst
        While Not .EOF
            strWhere = ""
            For i = 0 To .Fields.Count - 1
                strWhere = strWhere & .Fields(i).Name & "=" & "'" & Rst(i).Value & "'" & " AND "
            Next
     
            strSqlTMP = "SELECT * FROM " & TABLE_BRUTE & " WHERE " & Mid(strWhere, 1, Len(strWhere) - Len(" AND "))
            Set RstTMP = DB.OpenRecordset(strSqlTMP, DAO.dbOpenSnapshot)
     
                '
                ' nom de champs
                For intColIndex = 0 To RstTMP.Fields.Count - 1
     
                    Worksheets("wSheet").Range("A2").Offset(-1, intColIndex).Value = RstTMP.Fields(intColIndex).Name
     
                Next intColIndex
     
                    Worksheets("wSheet").Range("A2").CopyFromRecordset RstTMP
     
                RstTMP.Close
                Set RstTMP = Nothing
     
                '----  Traitement Xls -----
                 ' Quelques traitments
                '----------------------------
     
            End If
     
             '--- Supprimer les enregist de la table -----
             DB.Execute "DELETE * FROM " & TABLE_BRUTE & " WHERE " & Mid(strWhere, 1, Len(strWhere) - Len(" AND "))
             '---------------------------------------
     
            .MoveNext
     
        Wend
     
    '--- Nettoyage et libération mémoire
    .Close
    End With
    Set Rst = Nothing
     
    '---------------------
    DB.Close
     
    Set DB = Nothing
     
    End Sub

  4. #4
    Expert éminent sénior
    Avatar de Domi2
    Homme Profil pro
    Gestionnaire
    Inscrit en
    Juin 2006
    Messages
    7 194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Suisse

    Informations professionnelles :
    Activité : Gestionnaire
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 194
    Points : 16 044
    Points
    16 044
    Par défaut
    Bonjour,

    Tes tables sont dans la même base de données que l'application ou sont-elles liées ?

    Domi2

  5. #5
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut
    les tables sont dans la même base de données.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour

    Dans ton premier message tu n'avais pas dit que tu écrivais dans Excel

    Philippe

  7. #7
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut
    Oui, avec des besoins ultérieures. <effectuer des calculs dans Excel est devenu inévitable.

  8. #8
    Expert éminent sénior
    Avatar de Domi2
    Homme Profil pro
    Gestionnaire
    Inscrit en
    Juin 2006
    Messages
    7 194
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : Suisse

    Informations professionnelles :
    Activité : Gestionnaire
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 194
    Points : 16 044
    Points
    16 044
    Par défaut
    Bonjour,

    Déjà, je ne sais pas si cela à une incidence, mais j'essaierais de remplacer Set Rst = DB.OpenRecordset(strSql, DAO.dbOpenSnapshot) par Set Rst = DB.OpenRecordset(strSql).

    Par défaut, le type sera dbOpenTable, je serais curieux de savoir si cela a une influence sur la vitesse d'exécution sur une table de cette importance.

    Ensuite, pour voir, je retirerais toute la partie Excel et je ferais un test, de façon à déterminer si c'est cette partie qui est chronophage.

    Domi2

  9. #9
    Membre éprouvé

    Homme Profil pro
    Inscrit en
    Octobre 2009
    Messages
    789
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 56
    Localisation : France, Bas Rhin (Alsace)

    Informations forums :
    Inscription : Octobre 2009
    Messages : 789
    Points : 1 266
    Points
    1 266
    Par défaut
    Bonsoir,

    Autre idée : réalise toute ta procédure dans une table temporaire et exporte là ensuite dans un fichier Excel.

    Cordialement

    Christophe

  10. #10
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut
    Bonjour,

    Déjà, je ne sais pas si cela à une incidence, mais j'essaierais de remplacer Set Rst = DB.OpenRecordset(strSql, DAO.dbOpenSnapshot) par Set Rst = DB.OpenRecordset(strSql).

    Par défaut, le type sera dbOpenTable, je serais curieux de savoir si cela a une influence sur la vitesse d'exécution sur une table de cette importance.

    Ensuite, pour voir, je retirerais toute la partie Excel et je ferais un test, de façon à déterminer si c'est cette partie qui est chronophage.
    J'ai testé en enlevant le ---> celà n'a pas d'impact en termes de durée de traitement

    Aussi, la partie dure 15mn sur une durée total de 2h55mn
    Donc je pense que l'essentiel de l'effort doit se faire au niveau du code que j'ai posté.
    J'aimerais savoir s'il y a une autre démarche que celle que j'ai proposé?

    Merci por votre aide

  11. #11
    Membre régulier Avatar de zoopsys
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 68
    Points : 80
    Points
    80
    Par défaut
    Bonjour,

    Personnellement, pour proposer une autre solution, il faudrait comprendre le fonctionnel de ton code...

    si ton premier select te remonte 700 000 lignes :

    A la ligne 38 tu exécutes donc 700 000 select, où tu vas parcourir X champs
    puis tu exécutes 700 000 requête de suppression (à par si ta clause where te remonte plus d'une ligne), çà peut effectivement prendre beaucoup de temps...

    De plus ta base est en locale ou sur un réseau ?

  12. #12
    Rédacteur/Modérateur
    Avatar de loufab
    Homme Profil pro
    Entrepreneur en solutions informatiques viables et fonctionnelles.
    Inscrit en
    Avril 2005
    Messages
    12 068
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Entrepreneur en solutions informatiques viables et fonctionnelles.
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2005
    Messages : 12 068
    Points : 24 680
    Points
    24 680
    Par défaut
    Bonjour,
    Techniquement je ne vois pas ce qui peut être optimisé, à part le Join à la place de la boucle sur ChpCritere.

    Par contre d'un point de vue conceptuel, je n'arrive pas à comprendre la démarche.

    J'ai fait un test avec un échantillon de données simple. Et ce que ça me remmène me laisse à penser que tu pourrais t'en sortir beaucoup mieux avec du SQL pur.
    Voici mon échantillon vraiment bidon :
    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
     
    Id	Id_Client	NumeroFacture	Montant
    1      6	       1	                102.005	6	       1	                107.006	6	       1	                102.007	7	       2                	105.008	7	       2	                108.009	7	       2	                104.0010	8	       3	                107.0011	8	       3			104.0012	9	       4	                100.0013	9	       4	                109.0014	9	       4	                110.0015	9	       5	                101.0016	9	       5	                104.00
    Voici ce que j'obtiens avec le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Id	Id_Client	NumeroFacture	Montant
    1      6               1                      102 
    7      7               2                      105 
    10    8               3                      107 
    12    9               4                      100 
    15    9               5                      101
    Et maintenant la même chose avec 1 seule requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Id	        Id_Client	 NumeroFacture	Montant
    1	        6	         1	                102.007	        7	         2	                105.0010	        8	         3	                107.0012	        9	         4	                100.0015	        9       	 5               	101.00
    On peut donc en déduire, sauf erreur de ma part, que cette simple requête sera plus rapide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT Min(tFactures.Id) AS MinDeId, tFactures.Id_Client, tFactures.NumeroFacture, First(tFactures.Montant) AS PremierDeMontant
    FROM tFactures
    GROUP BY tFactures.Id_Client, tFactures.NumeroFacture;
    Comme je le dis souvent, 99% d'un problème se solutionne via SQL. Les 1% restant sont soit le fait d'un problème très complexe, soit d'une mauvaise conception du MCD. Avec une seule table je ne pense pas que l'on soit dans les 1% restant.

    Cordialement,

  13. #13
    Membre averti Avatar de casavba
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    455
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2007
    Messages : 455
    Points : 323
    Points
    323
    Par défaut
    Bonjour,

    Par contre d'un point de vue conceptuel, je n'arrive pas à comprendre la démarche.
    Le concept est de rapatrier des données dans Excel en fonction de critères bien définies et ensuite de faire des calculs complexes (Simplexe ... (Fonction quadratique) )

    Loufab, je te remercie pour la réponse Sql mais celle-ci ne répond pas au besoin.

    Par conséquent, je vais mettre cette discussion en Délestage vu que le problème de performance ne peut être résolu. [MS Access et le VBA sont limités pour ce genre de traitement. Peut-être basculé vers du C++ ou C#)

    Merci à tout le monde pour la contribution.

    Cordialement,

  14. #14
    Membre régulier Avatar de zoopsys
    Homme Profil pro
    Inscrit en
    Août 2008
    Messages
    68
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 68
    Points : 80
    Points
    80
    Par défaut
    As-tu identifié quelle(s) ligne(s) de code était consommatrice en temps ?

  15. #15
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2004
    Messages : 37
    Points : 48
    Points
    48
    Par défaut
    SQL est quelque peu inadapté pour ce genre de traitement !

    Je vous conseille d'indexer la table : un index par combinaison des critères de selection.

    Via l'index, vous pouvez vous positionnez dans la table avec un Seek

    Une boucle testant les critères de sélection et dans la boucle vous faites vos mise à jour.

    Cela aura pour effet de limiter les accès à la table au nombre d'enregistrements correspondant aux critères de sélection.

    Addenda : L'indexation peut être limitée à un seul critère, le plus restrictif (une date, par exemple), les autres critères pouvant être testés dans la boucle. Le but est de limiter les enregistrements lus.

Discussions similaires

  1. Temps d'execution trop lent : hive=> neo4j
    Par lobna20 dans le forum Développement de jobs
    Réponses: 3
    Dernier message: 03/03/2015, 12h38
  2. Programme de recherche temps d'execution trop long
    Par lucas67 dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 21/11/2007, 16h15
  3. Temps d'execution très lent
    Par bahiatoon dans le forum C++Builder
    Réponses: 16
    Dernier message: 20/07/2007, 00h45
  4. Temps d'execution trop long !
    Par taisherg dans le forum Access
    Réponses: 14
    Dernier message: 15/06/2007, 14h22
  5. [VBA-E]temps d execution trop lent
    Par chmod777 dans le forum Macros et VBA Excel
    Réponses: 7
    Dernier message: 08/03/2006, 16h10

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