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

C# Discussion :

[DataSet] Comparaison très lente


Sujet :

C#

  1. #1
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut [DataSet] Comparaison très lente
    Bonjour,

    Je suis en train de programmer un synchronisateur qui prend les données d'une base de données Acomba et les insert dans une base de données MySQL. Jusque la, tout est parfait. Mon problème arrive par la suite.

    Je dois comparer les données de ces base de données. J'ai donc rempli 2 DataSet et je compare mais cela est très mais très lent. J'ai prêt de 18,000 lignes et 155 colonnes (donc beaucoup de données) dans un DataSet et l'autre est vide alors il ca ne devrait pas être très long lors de la comparaison. C'est peut-être moi qui m'y prend mal mais la je ne sais plus du tout comment faire pour que cela sois un minimum rapide.

    Merci,
    Friedrick

    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
     
    private void firstpass(ref DataSet ds1, string pk1, ref DataSet ds2, string pk2)
    {
        //ds1 has priority
        for (int x = 0; x < ds1.Tables[0].Rows.Count; x++)
        {
            //check if row exist in ds2
            if (!this.isin(ds2, ds1.Tables[0].Rows[x][pk1].ToString(), pk2))
            {
                //primary key of ds1 does not match ds2
                DataRow newrow = ds2.Tables[0].NewRow();
                for (int c = 0; c < ds2.Tables[0].Columns.Count; c++)
                {
                    newrow[c] = ds1.Tables[0].Rows[x][c];
                    logBox.Text += ">>>New Data : " + ds1.Tables[0].Rows[x][c].ToString() + "\n";
                    scroll();
                }
                ds2.Tables[0].Rows.Add(newrow);
                //newrow.Delete();
            }
        }
    }

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    fait voir le code de ta méthode isin aussi

    pourquoi convertir la clé primaire en string pour la passer en paramètre de isin ?

    à mon avis ce qui est lent c'est surtout ta façon de copier les lignes, et la mise à jour de l'interface

    - pas la peine de copier colonne par colonne, il y a des moyens plus simples :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ds2.Tables[0].Rows.Add(ds1.Tables[0].Rows[x].ItemArray);
    - tu modifies un textbox dans une boucle où l'exécution va passer 155 * 18000 = 2790000 fois... Tu as vraiment besoin de logger chaque colonne de chaque ligne ? Pour quoi faire ? Tu vas vérifier visuellement les 2790000 lignes de log ?

  3. #3
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut
    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
     
    private bool isin(DataSet dsin, string pk, string pkfield)
    {
        //get collumn index
     
        for (int x = 0; x < dsin.Tables[0].Rows.Count; x++)
        {
            string t = dsin.Tables[0].Rows[x][pkfield].ToString();
     
            /*
             * check if pk or t are double or int convert both to double
             * and back to string
             */
            try
            { //pk is double
                pk = Double.Parse(pk).ToString();
                t = Double.Parse(t).ToString();
            }
            catch { }
     
            if (String.Compare(t, pk, true) == 0)
                return true;
        }
        return false;
    }
    Voici ma méthode isin. Non, je ne suis pas oublier de tout mettre dans un textbox, c'était simplement pour me débugger. Sinon, je n'ai aucune idée pourquoi la clé est changer en string. J'ai prit le code de mon collègue, car c'est lui qui l'a créer mais il nous a quitter alors, je ramasse les pots cassés . Non, sans rire, le programme original était en console et son système de configuration passait par des fichiers .dat sans aucune façon de modifier les DSN, les tables à sync, etc. J'ai donc mit un petit visuel simple!


    Merci, pour la façon de copier je ne la connaissais pas! Car le problème aussi c'est qu'il y a trois phase à faire:

    - La première ajouter les lignes de DS1 à DS2;
    - La deuxième supprime les lignes de DS2 qui ne sont pas dans DS1;
    - La troisième modifie le statut pour savoir si modifié, ajouté ou supprimé.

    Voici le code des mes 2 autres méthodes: http://pastebin.com/m2c6de39e

    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
     
    private void secondpass(ref DataSet ds1, string pk1, ref DataSet ds2, string pk2)
    {
        //ds1 has priority
        for (int x = 0; x < ds2.Tables[0].Rows.Count; x++)
        {
            //check if row exist in ds2
            if (!this.isin(ds1, ds2.Tables[0].Rows[x][pk2].ToString(), pk1))
            {
     
                //primary key of ds1 does not match ds2
                Console.WriteLine(">>>Deleting Data : " + ds2.Tables[0].Rows[x].ToString());
                ds2.Tables[0].Rows[x].Delete();
            }
        }
    }
    private void thirdpasss(ref DataSet ds1, string pk1,string[] fields1, ref DataSet ds2, string pk2,string[] fields2){
        /* if rowcount ds1 != ds2 throw
         * here we have to compare all row from ds1 to ds2,
         * for each row in ds1,
         *    for each field in fieldsa
         *    if ds2[row][fieldsb[index of fielda]] != ds1[row][field]
         *    ds2[row][[fieldsb[index of fielda]] = ds1[row][field]
         */
     
        if (this.getrcount(ds1) != this.getrcount(ds2))
            throw new ApplicationException("Row count dont match, cannot synchronize.Rerun pass 1 and 2");
        if (fields1.Count() != fields2.Count())
            throw new ApplicationException("fields count dont match, cannot synchronize.Check config");
        for (int r1=0; r1 < ds1.Tables[0].Rows.Count; r1++){
            if (ds1.Tables[0].Rows[r1].RowState == DataRowState.Deleted)
                continue;
            for (int f1 = 0; f1 < fields1.Count(); f1++){
                //first ensure that ds1 pk is in ds2
                // then get index of ds2
                //int r2index = this.getindex(ds2, ds1.Tables[0].Rows[r1][pk1].ToString(),pk1);
                int r2index = 0;
                if (r2index == -1)
                    throw new ApplicationException("Trying to synchronize pass 3, row not found in noprio ds, rerun pass1 and 2");
                L(ds2.Tables[0].Rows[0][1].ToString());
                string ds1str = "";
                string ds2str = "";
                ds1str = ds1.Tables[0].Rows[r1][fields1[f1]].ToString();
                ds2str = ds2.Tables[0].Rows[r2index][fields2[f1]].ToString();
                L("*******");
                Console.WriteLine(ds1str.ToString());
                Console.WriteLine(ds2str.ToString());
     
                if ( ds2str != ds1str){
                    Console.WriteLine("Field modified");
                    Console.WriteLine("ds1 :" + ds1.Tables[0].Rows[r1][fields1[f1]].ToString());
                    Console.WriteLine("ds2 :" + ds2.Tables[0].Rows[r2index][fields2[f1]].ToString());
                    ds2.Tables[0].Rows[r2index][fields1[f1]] = ds1.Tables[0].Rows[r1][fields1[f1]].ToString();
     
                }
     
            }
        }
     
    }

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Ben si tu revoies ce collègue un jour, balance lui ce code dans la gueule

    En plus de ceux que j'ai déjà indiqués, il y a un autre gros point de ralentissement dans la méthode isin : la recherche se fait par clé primaire, donc inutile de parcourir toute la table pour retrouver la ligne recherchée... La méthode Select permet d'effectuer une recherche dans une DataTable, et si la colonne est bien définie comme clé primaire, la recherche se fait par un index, donc beaucoup plus rapide (et plus simple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private bool isin(DataSet dsin, string pk, string pkfield)
    {
        DataRow[] rows = dsin.Tables[0].Select(pkfield + " = " + pk); // par exemple "id = 3"
        return rows.Count > 0;
    }
    Ca devrait déjà pas mal améliorer les performances. Mais à mon avis le plus important reste de dégager les mises à jour d'interfaces qui doivent prendre au moins 80% du temps...

    Mais franchement, je pense qu'au lieu d'essayer de récupérer un code pourri, tu ferais mieux de te former un peu sur l'utilisation des DataSets et de refaire le truc toi-même en repartant de zéro...

  5. #5
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut
    Merci pour ton aide! Je viens de faire les modifications et je test. J'ai repris l'application originale en mode console sans aucun debug alors cela devrait accéléré le processus.

    Pour ce qui est d'apprendre les DataSet, ouais c'est dans mes plans, mais la on manque de temps pour ce projet alors je fais mon possible .

    Je te redonnes des nouvelles et encore merci!

    Merci, Frédérick.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Au fait, tu as regardé la méthode DataSet.Merge ?
    Je sais pas si ça correspond à ton besoin, mais ça vaut le coup d'y jeter un oeil...

  7. #7
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut
    J'ai déjà essayé de l'utiliser:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    ds3.Merge(ds1);
    ds3.AcceptChanges();
    ds3.Merge(ds2);
    ds4 = ds3.GetChanges();
    C'est peut-être moi qui ne sais pas comment bien utiliser cette méthode mais mon DS4 est toujours null

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Ben en faisant AcceptChanges, tu "oublies" les changements faits par le premier Merge (dans le sens où tu oublies que c'est des changements, mais ils ne sont pas annulés). Donc si le merge avec ds2 n'introduit pas de changements, c'est normal que GetChanges ne renvoie rien...
    De toutes façons je ne pense pas que cette méthode puisse te convenir, parce que ça ne supprimera pas de lignes, ça ne fera qu'en ajouter

  9. #9
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut
    Oui je comprends mais lorsque je fais mes tests, je vide ma bdd MySQL et celle ce mon Acomba est pleine. J'ai donc DS1 plein et DS2 vide. Je met la priorité sur le DS1 (dans le code ci-haut j'ai inversé mais dans le mien c'était dans le bon ordre ), et il me retournait un DataSet vide. C'est peut-être (même probablement) moi car je ne suis pas le plus habitué en C# mais tout-de-même ca ne devrait pas etre très compliqué!

  10. #10
    Expert confirmé

    Avatar de Philippe Vialatte
    Homme Profil pro
    Architecte technique
    Inscrit en
    Juillet 2004
    Messages
    3 029
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Architecte technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juillet 2004
    Messages : 3 029
    Par défaut
    Sinon, ce serait peut-etre interessant de faire un truc genre :

    - 1 passe ou tu stockes tes n cles primaires du dataset 1 dans un tableau, de taille = au plus grand id de ton dataset -> ecriture et lecture en O(1)

    genre:
    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
     
    private double[] LoadPrimaryKeysFromDataset(Dataset sourceDs, string primaryKeyField){
     
    DataView dv = new dataview(sourceDs.Tables[0]);
    dv.sort=primaryKeyField + ", ASC";
    int maxIndex = Convert.ToInt32(dv[dv.count-1][primaryKeyField]);
     
    double[] result = new double[maxIndex];
     
    foreach (DataRow dr in sourceDs.Tables[0].Rows){
      double pkValue = (double)dr[primaryKeyField];
      result[pkValue] = pkValue ;
    }
     
    return result;
     
    }
    - 1 passe ou tu testes l'existence de tes n cles primaires du dataset 2 dans cette liste, si cela n'existe pas, tu les supprime



    -> comme ca, tu ne parcours plus le dataset, tu fais des
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    private bool isin(double[] referencePks, double primaryKey){
     return (referencePks[primaryKey] != 0);
    }
    Alors, c'est de l'optimisation a l'arrache, mais ca pourrait etre une piste

    (nb : code pas teste, tape a l'arrache dans le forum, si ca compile, c'est un miracle, si ca marche, c'en est un autre )

    Mon Blog

    The Cake is still a lie !!!



    Vous voulez contribuer à la rubrique .NET ? Contactez-moi par MP.
    Vous voulez rédiger des articles pour la rubrique .NET ? Voici la procédure à suivre.

  11. #11
    Membre confirmé
    Inscrit en
    Janvier 2008
    Messages
    106
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2008
    Messages : 106
    Par défaut
    Ouais c'est une bonne idée mais je crois que je vais optimiser mes recherches et je vais diminuer le nombre de colonne à synchroniser! Mais si quelqu'un a une autre solution à proposer, je suis tout oui!

  12. #12
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Par défaut
    Pourquoi tu n'utilises pas le Sync Framework ?
    Besoin d'un MessageBox amélioré ? InformationBox pour .NET 1.1, 2.0, 3.0, 3.5, 4.0 sous license Apache 2.0.

    Bonnes pratiques pour les accès aux données
    Débogage efficace en .NET
    LINQ to Objects : l'envers du décor

    Mon profil LinkedIn - MCT - MCPD WinForms - MCTS Applications Distribuées - MCTS WCF - MCTS WCF 4.0 - MCTS SQL Server 2008, Database Development - Mon blog - Twitter

Discussions similaires

  1. BDD sur réseau très très très lent...
    Par ericain dans le forum Access
    Réponses: 12
    Dernier message: 20/02/2015, 18h17
  2. Ouverture et fermeture de base très lent...
    Par Tofdelille dans le forum Installation
    Réponses: 6
    Dernier message: 19/09/2006, 19h51
  3. [Lomboz] Editeur jsp très lent
    Par lr dans le forum Eclipse Java
    Réponses: 10
    Dernier message: 29/01/2005, 20h43
  4. SQL Server trés lent
    Par arwen dans le forum MS SQL Server
    Réponses: 18
    Dernier message: 07/11/2003, 15h45

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