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

VB.NET Discussion :

Optimisation d'un traitement lourd [Débutant]


Sujet :

VB.NET

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2010
    Messages : 71
    Points : 47
    Points
    47
    Par défaut Optimisation d'un traitement lourd
    Bonsoir mes amis,
    j'ai un formulaire qui génère un fichier EXCEL pour les mouvements de stock de 1500 articles :

    Le problème c'est il prend beaucoup du temps environ 30 minutes et au même temps il se plante

    Voici le code de traitement que j'ai fait :
    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
    Private Sub traitement()
            Try
                Dim _date1 As New Date(DateTimePicker1.Value.Year, DateTimePicker1.Value.Month, DateTimePicker1.Value.Day, 0, 0, 0)
                Dim _date2 As New Date(DateTimePicker2.Value.Year, DateTimePicker2.Value.Month, DateTimePicker2.Value.Day, 23, 59, 59)
     
                Dim articles As New DataTable
                articles = db_centrale_foxpro.execute_select("select code,libelle,0.O,0.O,0.0,0.0,0.0 from article order by code asc")
     
                Dim ligne As DataRow = dernierInventaire()
                Dim code_inventaire As String = ligne.Item(0)
                Dim date_inventaire As Date = ligne.Item(1)
     
                Dim tampxls As New StringBuilder()
                tampxls.Append(vbTab).Append(vbTab).Append("MOUVEMENT DES ARTICLES   ").Append(vbTab).Append(vbTab).Append(vbTab).Append("Exporter Le:").Append(vbTab).Append(Date.Now()).Append(vbCr).Append(vbCr)
                tampxls.Append("Magasin :").Append(vbTab).Append(liste_depots.Text.ToString).Append(vbCr).Append(vbCr)
                tampxls.Append("Du").Append(vbTab).Append(DateTimePicker1.Value.Date.ToString).Append(vbTab).Append("A").Append(vbTab).Append(DateTimePicker2.Value.Date.ToString).Append(vbCr).Append(vbCr)
                tampxls.Append("code").Append(vbTab).Append("libelle").Append(vbTab).Append(vbTab).Append(vbTab).Append("QteInitial").Append(vbTab).Append("QteEntrer").Append(vbTab).Append("QteSortie").Append(vbTab).Append("CA").Append(vbTab).Append("StokFinal").Append(vbTab).Append(vbTab).Append(vbCr)
     
     
                For Each article As DataRow In articles.Rows
                    If article.Item(0).ToString.Trim <> "" Then
                        'qte initial
                        article.Item(2) = (qteInventaire(article.Item(0).ToString, code_inventaire) + qteInterDepot(article.Item(0).ToString, date_inventaire, _date1) + qteBonRetour(article.Item(0).ToString, date_inventaire, _date1)) - qteBonLivraison(article.Item(0).ToString, date_inventaire, _date1)
                        'qte entrer
                        article.Item(3) = qteInterDepot(article.Item(0).ToString, _date1, _date2) + qteBonRetour(article.Item(0).ToString, _date1, _date2)
                        'qte sortie
                        article.Item(4) = qteBonLivraison(article.Item(0).ToString, _date1, _date2)
                        'CA
                        article.Item(5) = chiffreAffaire(article.Item(0).ToString, _date1, _date2)
                        'stock final
                        article.Item(6) = (article.Item(2) + article.Item(3)) - article.Item(4)
     
     
                        tampxls.Append(article.Item(0).ToString).Append(vbTab)
                        tampxls.Append(article.Item(1).ToString).Append(vbTab).Append(vbTab).Append(vbTab)
                        tampxls.Append(article.Item(2).ToString).Append(vbTab)
                        tampxls.Append(article.Item(3).ToString).Append(vbTab)
                        tampxls.Append(article.Item(4).ToString).Append(vbTab)
                        tampxls.Append(article.Item(5).ToString).Append(vbTab)
                        tampxls.Append(article.Item(6).ToString).Append(vbTab).Append(vbCr)
     
                    End If
                Next
     
     
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL CA :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL QteSortie :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL QteEntrer :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
     
     
                RichTextBox1.Text = tampxls.ToString()
                RichTextBox1.SaveFile("fichier.xls", RichTextBoxStreamType.PlainText)
            Catch ex As Exception
                MessageBox.Show(ex.Message, "ERREUR", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    Voici un exemple d'une fonction parmi les fonctions que j'ai utilisé dans le traitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Private Function qteBonLivraison(ByVal code_article As String, ByVal date1 As Date, ByVal date2 As Date) As Decimal
            Dim qte As Decimal
            Try
                qte = db_centrale_foxpro.valeurUnique("SELECT SUM(lblivre.qte) FROM lblivre WHERE lblivre.code='" & code_article & "' AND lblivre.nbl in (SELECT nbl FROM bonlivra WHERE bonlivra.depote=" & liste_depots.SelectedValue.ToString & " AND bonlivra.valide =.T. AND bonlivra.date BETWEEN " & General.toDateFoxPro(date1) & " AND " & General.toDateFoxPro(date2) & ")")
            Catch ex As Exception
                qte = 0
            End Try
            Return qte
        End Function
    Merci de votre aide ^^
    Images attachées Images attachées   

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    tu peux utiliser un chronomètre (system.diagnostics.stopwatch (.Start .Stop .ElapsedMillisecondes)) pour voir quelle partie du code est longue

    après on verra comment modifier le code qui est long
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Juste une petite remarque.
    Il est souvent possible de faire une énorme partie du travail directement dans la requête. Ca donne des requêtes énorme mais le temps de travail est drastiquement diminué.
    En héritant d'un projet d'un collègue qui devait exporter énormément de données provenant d'énormément de tables différentes, j'ai modifié son code qui faisait comme vous, c'est à dire que pour chaque ligne d'une première requête il exécutait une dizaine d'autre requête. J'ai tout mi dans une seul requête. Résultat, je suis passé d'un traitement de 4 heures à un traitement de 5 minutes !!!

    Déjà ici les deux requêtes que vous donnez pourrait déjà être rassemblées dans une seule.

    Autre piste d'amélioration, passer par un datareader au lieu d'un dataTable. Car il commence à traiter chaque ligne directement sans attendre d'avoir tout rapatrié en mémoir (ca prend du temps pour beaucoup de donnée) et ca rend le programme beaucoup moins gourmand en mémoire (il ne stocke qu'une ligne à la fois)

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ah oui j'avais même pas fait gaffe qu'il y avait de la sous requete, il ne faut pas chercher plus loin

    les jointures (inner join et autres) permettent de faire des requetes sur plusieurs tables
    le sum nécessitera alors un group by en fin de requete

    pourquoi dans le 1er select mettre des 0.0, si la valeur est fixe, vous la connaissez, ca ne sert à rien de dire à la base de vous le rapatrier pour chaque ligne
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre averti Avatar de Saintelaitlait
    Homme Profil pro
    Responsable ServiceDesk
    Inscrit en
    Août 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Canada

    Informations professionnelles :
    Activité : Responsable ServiceDesk
    Secteur : Service public

    Informations forums :
    Inscription : Août 2011
    Messages : 179
    Points : 355
    Points
    355
    Par défaut
    Juste comme ca, sans améliorations de performances, mais améliorations de la lisibilité et de la stabilité.

    Pense à utiliser des requêtes paramètrées. Ca t'évitera de planter si une valeur que tu concatène contient un apostrophe.

    Et ce sera beaucoup plus facile à lire

    Plus d'infos ici
    http://webman.developpez.com/article...rameter/vbnet/
    Logic is like the sword -- those who appeal to it, shall perish by it.

  6. #6
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    les jointures (inner join et autres) permettent de faire des requetes sur plusieurs tables
    le sum nécessitera alors un group by en fin de requete
    Tout à fait, il y a aussi les sous-requêtes, les tables temporaires avec l'instruction With...

    Citation Envoyé par Pol63 Voir le message
    pourquoi dans le 1er select mettre des 0.0, si la valeur est fixe, vous la connaissez, ca ne sert à rien de dire à la base de vous le rapatrier pour chaque ligne
    C'est utilisé pour avoir des colonnes pour faire des calculs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
                        'qte initial
                        article.Item(2) = (qteInventaire(article.Item(0).ToString, code_inventaire) + qteInterDepot(article.Item(0).ToString, date_inventaire, _date1) + qteBonRetour(article.Item(0).ToString, date_inventaire, _date1)) - qteBonLivraison(article.Item(0).ToString, date_inventaire, _date1)
                        'qte entrer
                        article.Item(3) = qteInterDepot(article.Item(0).ToString, _date1, _date2) + qteBonRetour(article.Item(0).ToString, _date1, _date2)
                        'qte sortie
                        article.Item(4) = qteBonLivraison(article.Item(0).ToString, _date1, _date2)
                        'CA
                        article.Item(5) = chiffreAffaire(article.Item(0).ToString, _date1, _date2)
                        'stock final
                        article.Item(6) = (article.Item(2) + article.Item(3)) - article.Item(4)
    Mais il est vrais que ce n'est pas du tout la bonne solution, sachant que toutes ces données vont transiter sur le réseau, et augmenté le temps de chargement du dataTable (Qu'il serait judicieux de remplacer par un DataReader pour préserver la mémoire et éviter le plantage)

    Il faudrait aussi, si ce n'est déjà fait, faire le traitement dans un thread séparé via par exemple un BackgroundWorker afin de ne pas figer l'application.

    zaghi va avoir du travail demain

  7. #7
    Expert éminent Avatar de Graffito
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    5 993
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 5 993
    Points : 7 903
    Points
    7 903
    Par défaut
    j'ai un formulaire qui génère un fichier EXCEL
    Est-ce que le temps est significativement réduit si on n'opère pas les affectations aux cellules Excel ?
    " Le croquemitaine ! Aaaaaah ! Où ça ? " ©Homer Simpson

  8. #8
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2010
    Messages : 71
    Points : 47
    Points
    47
    Par défaut
    D'abord merci pour vos réponses, j'ai utilisé un chronomètre stopwatch pour voir quelle partie du code est longue et j'ai comme résultat que le for each prend environ 30 minutes donc après vos réponses j'ai changer datatable par DataReader voici le nouveau code :
    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
        Private Sub traitement()
            Try
                Dim ligne As DataRow = dernierInventaire()
                Dim code_inventaire As String = ligne.Item(0)
                Dim date_inventaire As Date = ligne.Item(1)
     
                Dim _date1 As New Date(DateTimePicker1.Value.Year, DateTimePicker1.Value.Month, DateTimePicker1.Value.Day, 0, 0, 0)
                Dim _date2 As New Date(DateTimePicker2.Value.Year, DateTimePicker2.Value.Month, DateTimePicker2.Value.Day, 23, 59, 59)
     
                Dim article As Data.OleDb.OleDbDataReader
     
                Dim cnx As New Data.OleDb.OleDbConnection(db_centrale_foxpro.connexion.ConnectionString)
                Dim cmd As New Data.OleDb.OleDbCommand("select code,libelle from article order by code asc", cnx)
                cnx.Open()
                article = cmd.ExecuteReader
     
     
                Dim tampxls As New StringBuilder()
                tampxls.Append(vbTab).Append(vbTab).Append("MOUVEMENT DES ARTICLES   ").Append(vbTab).Append(vbTab).Append(vbTab).Append("Exporter Le:").Append(vbTab).Append(Date.Now()).Append(vbCr).Append(vbCr)
                tampxls.Append("Magasin :").Append(vbTab).Append(liste_depots.Text.ToString).Append(vbCr).Append(vbCr)
                tampxls.Append("Du").Append(vbTab).Append(DateTimePicker1.Value.Date.ToString).Append(vbTab).Append("A").Append(vbTab).Append(DateTimePicker2.Value.Date.ToString).Append(vbCr).Append(vbCr)
                tampxls.Append("code").Append(vbTab).Append("libelle").Append(vbTab).Append(vbTab).Append(vbTab).Append("QteInitial").Append(vbTab).Append("QteEntrer").Append(vbTab).Append("QteSortie").Append(vbTab).Append("CA").Append(vbTab).Append("StokFinal").Append(vbTab).Append(vbTab).Append(vbCr)
     
                Dim a As New Stopwatch
                a.Start()
     
                Dim qte_initial, qte_entrer, qte_sortie, chiffre_affaire, stock_final As Decimal
                Dim code_article, libelle_article As String
     
                While article.Read
                    code_article = article.GetString(0)
                    libelle_article = article.GetString(1)
     
                    If code_article.Trim <> "" Then
     
                        qte_initial = (qteInventaire(code_article, code_inventaire) + qteInterDepot(code_article, date_inventaire, _date1) + qteBonRetour(code_article, date_inventaire, _date1)) - qteBonLivraison(code_article, date_inventaire, _date1)
     
                        qte_entrer = qteInterDepot(code_article, _date1, _date2) + qteBonRetour(code_article, _date1, _date2)
     
                        qte_sortie = qteBonLivraison(code_article, _date1, _date2)
     
                        chiffre_affaire = chiffreAffaire(code_article, _date1, _date2)
     
                        stock_final = (qte_initial + qte_entrer) - qte_sortie
     
     
                        tampxls.Append(code_article).Append(vbTab)
                        tampxls.Append(libelle_article).Append(vbTab).Append(vbTab).Append(vbTab)
                        tampxls.Append(qte_initial.ToString).Append(vbTab)
                        tampxls.Append(qte_entrer.ToString).Append(vbTab)
                        tampxls.Append(qte_sortie.ToString).Append(vbTab)
                        tampxls.Append(chiffre_affaire.ToString).Append(vbTab)
                        tampxls.Append(stock_final.ToString).Append(vbTab).Append(vbCr)
     
                    End If
                End While
     
                article.Close()
                cnx.Close()
     
                a.Stop()
                MsgBox(a.ElapsedMilliseconds / 60000)
     
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL CA :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL QteSortie :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
                tampxls.Append(vbCr).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append(vbTab).Append("TOTAL QteEntrer :").Append(vbTab).Append(vbTab).Append("0.0").Append(vbCr)
     
     
                RichTextBox1.Text = tampxls.ToString()
                RichTextBox1.SaveFile("fichier.xls", RichTextBoxStreamType.PlainText)
            Catch ex As Exception
                MessageBox.Show(ex.Message, "ERREUR", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    le résultat : environ 25 minutes (-5 min par rapport a l'autre ) mais toujours il se plante :
    Images attachées Images attachées  

  9. #9
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Essaye de lancer l'application à partir d'un backgroundworker car windows regarde si le thread répond et ici vu que tu fais un lourd traitement sur le même thread que l'interface, il pourrait croire que c'est planter (d'ou le message "ne répond pas") alors qu'il est toujours occupé à faire le traitement...

  10. #10
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    as tu essayé de réunir toutes les requetes en une seule ?
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2010
    Messages : 71
    Points : 47
    Points
    47
    Par défaut
    Citation Envoyé par Sankasssss Voir le message
    Essaye de lancer l'application à partir d'un backgroundworker car windows regarde si le thread répond et ici vu que tu fais un lourd traitement sur le même thread que l'interface, il pourrait croire que c'est planter (d'ou le message "ne répond pas") alors qu'il est toujours occupé à faire le traitement...
    j'ai lancer le traitement à partir d'un backgroundworker,le temps d’exécution c'est 19 minutes avec une mauvaise erreur :
    Le CLR n'a pas pu effectuer de transition du contexte COM 0x457a98 au contexte COM 0x457c08 pendant 60 secondes. Le thread qui possède le contexte/cloisonnement de destination est probablement en train d'attendre ou de traiter une opération très longue sans pompage des messages Windows. Cette situation a généralement des effets négatifs sur les

  12. #12
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Est-ce que ton code atteint la ligne 62 de ton poste n°8?
    C'est à dire le msgbox qui montre le temps?

    Si c'est le cas c'est qu'il y a une erreur après...

  13. #13
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2010
    Messages : 71
    Points : 47
    Points
    47
    Par défaut
    Citation Envoyé par Sankasssss Voir le message
    Est-ce que ton code atteint la ligne 62 de ton poste n°8?
    C'est à dire le msgbox qui montre le temps?

    Si c'est le cas c'est qu'il y a une erreur après...
    j'ai réglé l'erreur , mais maintenant est ce qu'il y a une solution pour que la boucle for each prend moins de temps ?

  14. #14
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Citation Envoyé par zaghi Voir le message
    est ce qu'il y a une solution pour que la boucle for each prend moins de temps ?
    Oui :
    Citation Envoyé par Sankasssss Voir le message
    Juste une petite remarque.
    Il est souvent possible de faire une énorme partie du travail directement dans la requête. Ca donne des requêtes énorme mais le temps de travail est drastiquement diminué.
    En héritant d'un projet d'un collègue qui devait exporter énormément de données provenant d'énormément de tables différentes, j'ai modifié son code qui faisait comme vous, c'est à dire que pour chaque ligne d'une première requête il exécutait une dizaine d'autre requête. J'ai tout mi dans une seul requête. Résultat, je suis passé d'un traitement de 4 heures à un traitement de 5 minutes !!!

    Déjà ici les deux requêtes que vous donnez pourrait déjà être rassemblées dans une seule.
    Citation Envoyé par Sankasssss Voir le message
    ...
    Mais il est vrais que ce n'est pas du tout la bonne solution, sachant que toutes ces données vont transiter sur le réseau, et augmenté le temps de chargement du dataTable (Qu'il serait judicieux de remplacer par un DataReader pour préserver la mémoire et éviter le plantage)

    ...
    Citation Envoyé par Pol63 Voir le message
    as tu essayé de réunir toutes les requetes en une seule ?
    C'est déjà un très bon début non?

  15. #15
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2010
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2010
    Messages : 71
    Points : 47
    Points
    47
    Par défaut
    j'ai modifier datatable en datareader mais rien change, donc je vais essayer de faire en une seul requete mais je vois que ces très difficile

  16. #16
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Oui je sais qu'au début c'est pas facile, mais une fois que l'on sait le faire c'est réellement plus rapide...

    Le tout est de bien structurer la requête et de la tester au fur et à mesure que l'on ajoute des infos.

    Exemple d'indentation que j'emploi personnellement :

    Code sql : 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
    select 
        code,libelle,
        (
            select SUM(lblivre.qte)
            from lblivre
            where lblivre.code=? AND lblivre.nbl in 
                (  
                    SELECT nbl 
                    FROM bonlivra 
                    WHERE bonlivra.depote=? 
                        AND bonlivra.valide =.T. 
                        AND bonlivra.date BETWEEN ? AND ?
                )
        ) as sum_livre
    from article 
    order by code asc

    Cette requête ne fonctionnera pas car je ne connais pas les lien entre les tables, c'est à titre d'exemple pour une bonne lisibilité.

    N'hésites pas à utiliser les requêtes paramétrées (dans ma requête c'est les ?), c'est une très bonne pratique à avoir.

  17. #17
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    si on repars de ton premier post

    1ère requete :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT code,libelle 
        FROM article 
        ORDER BY code ASC

    requete pour chaque article :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT SUM(lblivre.qte) 
        FROM lblivre 
        WHERE lblivre.code='" & code_article & "' AND lblivre.nbl in (SELECT nbl FROM bonlivra WHERE bonlivra.depote=" & liste_depots.SelectedValue.ToString & " AND bonlivra.valide =.T. AND bonlivra.date BETWEEN " & General.toDateFoxPro(date1) & " AND " & General.toDateFoxPro(date2) & ")")
    en une seule ca donne :
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    select article.code,libelle, SUM(lblivre.qte) as qtebonlibvraison
        from article 
           INNER JOIN lblivre ON lblivre.code = article.code
        WHERE lblivre.code='" & code_article & "' AND lblivre.nbl in (SELECT nbl FROM bonlivra WHERE bonlivra.depote=" & liste_depots.SelectedValue.ToString & " AND bonlivra.valide =.T. AND bonlivra.date BETWEEN " & General.toDateFoxPro(date1) & " AND " & General.toDateFoxPro(date2) & ")")
         group by article.code, libelle
        order by code asc
    si chacune de tes fonctions exécute une requete il va falloir les mixer avec celle là

    au final si tu as une seule requete et les bons indexes sur la base de données, pour 1500 lignes ca devrait faire un temps de l'ordre de la seconde
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  18. #18
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    En réponse à Pol63,

    Cette solution par groupement serait bonne si on se limitait à ces deux requêtes, mais si on regarde cette partie de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
                        qte_initial = (qteInventaire(code_article, code_inventaire) + qteInterDepot(code_article, date_inventaire, _date1) + qteBonRetour(code_article, date_inventaire, _date1)) - qteBonLivraison(code_article, date_inventaire, _date1) 
                        qte_entrer = qteInterDepot(code_article, _date1, _date2) + qteBonRetour(code_article, _date1, _date2) 
                        qte_sortie = qteBonLivraison(code_article, _date1, _date2) 
                        chiffre_affaire = chiffreAffaire(code_article, _date1, _date2) 
                        stock_final = (qte_initial + qte_entrer) - qte_sortie
    On peut s'imaginer qu'il y a d'autre table à lier, c'est pour cela que dans ce genre de cas je préfère partir sur des champs créé avec des sous-requêtes comme celle montré dans mon poste précédent qui adaptée à ce que tu as donné donnerait :
    Code sql : 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
    SELECT 
        code,libelle,
        ( -- Début de sous requête
            SELECT SUM(lblivre.qte)
            FROM lblivre
            WHERE lblivre.code=article.code 
               AND lblivre.nbl IN 
                (  
                    SELECT nbl 
                    FROM bonlivra 
                    WHERE bonlivra.depote=? 
                        AND bonlivra.valide =.T. 
                        AND bonlivra.date BETWEEN ? AND ?
                )
        ) AS sum_livre -- Fin de sous requête qui est maintenant considérée comme un champ
    FROM article 
    ORDER BY code ASC

    On peut de cette manière multiplier les champs malgré des groupements différent de multiples autres sous totaux...

  19. #19
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ta requete est certes plus lisible, mais dans la plupart des cas elle est loin d'être optimisé
    il faudrait demander sur le forum sql server pour savoir si sql server peut faire un plan d'exécution comme si c'était une jointure, mais il me semble bien que la sous requete va être exécutée pour chaque article.code, donc quasiment comme le code découpé dans le programme (légèrement mieux certes)

    avec jointure c'est ce qu'il y a de plus optimisé
    même le with n'est pas toujours aussi efficace quand il peut être évité

    même le IN (sous requete) j'ai déjà vu des cas où avec un left join et un is not null c'était plus rapide
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  20. #20
    Modérateur
    Avatar de Sankasssss
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 842
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 842
    Points : 4 232
    Points
    4 232
    Par défaut
    Je suis à 100% d'accord avec toi qu'il faut essayé d'éviter tant que possible les with, like, in, substr...
    Mais pour avoir pondu des requêtes faisant 3 écran avec des with et des sous-requêtes, je sais que dans certain cas, il n'y a pas moyen de faire autrement.

    Pour donner la requête optimum, il faudrait voir la totalité des requêtes exécutées dans chaque méthode.

    Je rejoint ton avis que le forum SQL server serait plus adapter pour répondre à cette demande.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 7
    Dernier message: 03/05/2013, 20h15
  2. [MySQL] Optimisation d'un traitement arrêté par mon hébergeur
    Par lodan dans le forum PHP & Base de données
    Réponses: 17
    Dernier message: 27/02/2007, 20h37
  3. [Collection] Optimisation d'un traitement multithreads
    Par in dans le forum Collection et Stream
    Réponses: 6
    Dernier message: 30/11/2006, 10h28
  4. [C++/VB.Net]Optimiser des traitements lourds
    Par NiamorH dans le forum Windows Forms
    Réponses: 8
    Dernier message: 28/05/2006, 10h03
  5. [XSL] Optimisation d'un traitement de chaines de caractères
    Par mathieu dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 05/02/2006, 18h57

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