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 :

C# - BD : mode connecté ou non-connecté


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Par défaut C# - BD : mode connecté ou non-connecté
    Bonjour,

    J'ai réalisé un code en application console qui permet de répliquer une base de données Oracle vers une base de données MySql.

    Voici mon principe :

    *Ouverture des connexions aux BD (Oracle et MySql)

    *Lister toutes les tables Oracle et les stocker dans un tableau créé dynamiquement en fonction du nombre de tables listées

    *Boucler sur le tableau pour traiter chaque table Oracle séparément

    *Récupérer le schéma de la table courante Oracle (nom, type, longueur, nullable)

    *Vérifier la présence de la table courante Oracle dans MySql

    *Si la table courante n'existe pas dans MySql, je la crée avec son schéma associé

    *Si la table courante existe dans MySql, je vérifie que le schéma est identique

    *Ensuite, je boucle sur le tableau qui contient le schéma de la table courante pour pouvoir traiter chaque colonne séparément. Je fais un SELECT pour obtenir toutes les lignes de la colonne courante de la table courante ET l'ID correspondant (qui est tout simplement la 1ère colonne de la table).

    *Je vérifie la présence de l'ID dans la table MySql

    *Si l'ID n'existe pas, je le crée

    *J'update les valeurs en fonction de l'ID

    *Fermeture des connexions aux BD

    J'utilise à chaque fois des DataReader, et dès que je sors de la boucle qui me permet de récupérer les données, je réalise un "dispose()" pour libérer les ressources. Exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     Mcmddata = "UPDATE " + tname[i] + " SET " + tschemaO[j, 0] + " = @data WHERE " + tschemaO[0, 0] + " = @id";
                                //Console.WriteLine("La requete d'update est : " + Mcmddata);
                                cmdupdata = Command(Mcmddata, Mconnect);
                                cmdupdata.Parameters.Add(AjoutParametre("@id", Odata[tschemaO[0, 0]].ToString(), cmdupdata));
                                cmdupdata.Parameters.Add(AjoutParametre("@data", Odata[tschemaO[j, 0]].ToString(), cmdupdata));
                                ExecuteNonQuery(cmdupdata);
     
                                cmdupdata.Dispose();
     
                            }
    ou
    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
    string[,] tschemaM = new string[1, 3];
                                string cmd = "SHOW FIELDS FROM " + tname[i] + " WHERE FIELD=@nomchamps";
                                DbCommand McmdSchema = Command(cmd, Mconnect);
                                McmdSchema.Parameters.Add(AjoutParametre("nomchamps", tschemaO[j, 0], McmdSchema)); //tschemaO[j,0] contient le nom d'un champs d'une table
                                //Console.WriteLine("La table MySql est : " + tname[i]);
                                //Console.WriteLine("Le champs MySql est : " + tschemaO[j,0]);
                                DbDataReader MSchemaReader = ExecuteQuery(McmdSchema);
                                int cptrowMSchema = 0;
                                while (MSchemaReader.Read())
                                {
                                    //Console.WriteLine("je passe dans le while");
                                    cptrowMSchema++;
                                    tschemaM[0, 0] = MSchemaReader["Field"].ToString();
                                    tschemaM[0, 1] = MSchemaReader["Type"].ToString();
                                    tschemaM[0, 2] = MSchemaReader["Null"].ToString();
                                }
                                MSchemaReader.Dispose();

    Ma base de données Oracle est assez conséquente : 145 tables, + de 20000 lignes / table, et un nombre de colonnes qui varient de 5 -> 60...

    Après 4h, la 3ème table n'est toujours pas complète.

    Je me demandais s'il ne serait pas plus rapide d'utiliser des DataSet plutôt que des DataReader comme je fais et d'ouvrir/fermer les connexions quand j'en ai besoin.

    Merci.

  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 : 43
    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
    Citation Envoyé par rousseau_damien Voir le message
    Je me demandais s'il ne serait pas plus rapide d'utiliser des DataSet plutôt que des DataReader comme je fais
    Comment tu crois que le DataAdapter remplit un DataSet ? Il utilise lui-même un DataReader
    Donc non, c'est pas plus rapide, ça utilisera juste plus de RAM

    Citation Envoyé par rousseau_damien Voir le message
    et d'ouvrir/fermer les connexions quand j'en ai besoin.
    Je pense pas que ça change grand chose au niveau des perfs... Par contre, on considère généralement que c'est plus propre d'ouvrir la connexion au dernier moment et de la fermer dès qu'on n'en a plus besoin, donc tu peux le faire quand même.

    Au passage, pour être bien sûr de fermer tes DataReaders, commandes et connexions, prends l'habitude d'utiliser des blocs using :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    using (var reader = command.ExecuteReader())
    {
        ...
    }
    Ca appelle implicitement Dispose à la fin du bloc, même si une exception se produit.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 197
    Par défaut
    pas lu, mais pour remplir une base de données à partir d'une autre, il est plus performant de le faire directement que de stocker les données en ram dans une appli
    je ne sais pas si c'est possible entre mysql et oracle, mais par exemple dans sql server il est possible de créer un server lié et donc de faire des requetes inter base inter server genre "insert into server1.base1.table 1 select * from server2.base2.table1"
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  4. #4
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par rousseau_damien Voir le message
    Je me demandais s'il ne serait pas plus rapide d'utiliser des DataSet plutôt que des DataReader comme je fais et d'ouvrir/fermer les connexions quand j'en ai besoin.

    Merci.
    Ce qui serait à la base plus rapide, ce serait de ne pas passer par une application tiers "faite à la maison" pour faire des transferts de données entre deux SGBDR.

    Je ne connais pas MySql et plus vraiment Oracle (m'étant arrêté sans regret à la version 9.kelkchoz) , mais je doute fortement qu'aucun des deux ne dispose d'un outil type ETL pour faire ce genre de boulot.

    Accessoirement, même l'ETL de Sql Server (SSIS) doit être capable de consommer Oracle ou MySql et de "vider" dans MySql ou Oracle.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    38
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 38
    Par défaut
    bon perso je bosse sur des bases SQL Server avec plus de 14 000 000 de tuples et pas de délai ausi long sur les traitements... Ca dépend aussi de ta version d'Oracle et de MySQL. Ce sont des versions open source ? Peut être que ça peut ralentir un peu les données...

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 71
    Par défaut
    Bonjour,

    Merci pour ces réponses.

    J'utilise Oracle 9.2i.

    J'ai modifié mon code pour n'avoir qu'une seule connexion ouverte à la fois : avant je lisais les tables Oracle et pendant la lecture, je vérifiais la présence de l'ID dans la table MySql, je fesais un INSERT s'il n'y était pas, et ensuite l'UPDATE ligne/ligne de la 1ère colonne, ensuite de la 2ème, etc.

    Maintenant, je réalise une boucle qui va me permettre de de SELECT l'entièreté d'une table (comme si je faisais un SELECT *), le tout est stocké dans un DataSet, je ferme la connexion Oracle.

    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
    param="";
                    Orequete = "";
                    for (int j = 0; j < Odstschema.Tables[0].Rows.Count; j++)
                    {
                        if (j == 0)
                            param = Odstschema.Tables[0].Rows[j]["cn"].ToString();
                        else
                            param = " , " + Odstschema.Tables[0].Rows[j]["cn"].ToString();
     
                        Orequete = Orequete + param;
                    }
     
                    Orequete = "SELECT " + Orequete + " FROM " + Odstname.Tables[0].Rows[i]["tname"];
                    Oadapter.SelectCommand = dbo.Command(Orequete, Oconnect);
                    Oadapter.Fill(Odsdata);
     
                    Oadapter.Dispose();
                    dbo.Deconnec(Oconnect);
    Ensuite, je commence une boucle de 0 -> nblignes de mon DataSet.
    Je regarde la présence de l'ID dans la table MySql.
    S'il n'existe pas, je l'INSERT.
    Je réalise une boucle afin de créer une requête qui va m'UPDATE ligne/ligne toutes les colonnes de la table MySql
    J'envoi la requête.
    Je ferme ma boucle


    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
     
     
    param="";
                    Orequete = "";
                    for (int j = 0; j < Odstschema.Tables[0].Rows.Count; j++)
                    {
                        if (j == 0)
                            param = Odstschema.Tables[0].Rows[j]["cn"].ToString();
                        else
                            param = " , " + Odstschema.Tables[0].Rows[j]["cn"].ToString();
     
                        Orequete = Orequete + param;
                    }
     
                    Orequete = "SELECT " + Orequete + " FROM " + Odstname.Tables[0].Rows[i]["tname"];
                    Oadapter.SelectCommand = dbo.Command(Orequete, Oconnect);
                    Oadapter.Fill(Odsdata);
     
                    Oadapter.Dispose();
                    dbo.Deconnec(Oconnect);
     
                    for (int k = 0; k < Odsdata.Tables[0].Rows.Count; k++)
                    {
                        Mrequete = "SELECT " + Odstschema.Tables[0].Rows[0]["cn"] + " FROM " + Odstname.Tables[0].Rows[i]["tname"] + " WHERE " + Odstschema.Tables[0].Rows[0]["cn"] + " = @id ";
                        Madapter.SelectCommand = dbo.Command(Mrequete, Mconnect);
                        Madapter.SelectCommand.Parameters.Add(dbo.AjoutParametre("id", Odsdata.Tables[0].Rows[k][0], Madapter.SelectCommand));            //appel de la méthode AjoutParametre pour ajouter les paramètres dans la requete
                        Madapter.Fill(Mdsdata);
                        Madapter.Dispose();
                        dbo.Deconnec(Mconnect);
     
                        if (Mdsdata.Tables[0].Rows.Count == 0)
                        {
                            Mrequete = "INSERT INTO " + Odstname.Tables[0].Rows[i]["tname"] + " (" + Odstschema.Tables[0].Rows[0]["cn"] + ") VALUES (@id)";
                            MinsertID = dbo.Command(Mrequete, Mconnect);
                            MinsertID.Parameters.Add(dbo.AjoutParametre("id", Odsdata.Tables[0].Rows[k][0], MinsertID));
                            dbo.ExecuteNonQuery(MinsertID, Mconnect);
                            MinsertID.Dispose();
                        }
     
                        param="";
                        Mrequete ="";
                        for (int j = 1; j < Odstschema.Tables[0].Rows.Count; j++)
                        {
                            if (j == 1)
                            {
                                param = Odstschema.Tables[0].Rows[j]["cn"] + " = @value"+j;
                            }
                            else
                            {
                                param = " , " + Odstschema.Tables[0].Rows[j]["cn"] + " = @value"+j; 
                            }
     
                            Mrequete = Mrequete + param ;
                        }
     
                        Mrequete = "UPDATE " + Odstname.Tables[0].Rows[i]["tname"] + " SET " + Mrequete + " WHERE " + Odstschema.Tables[0].Rows[0]["cn"] + " = @id ";
     
                        Console.WriteLine(Mrequete);
     
     
                        updata = dbo.Command(Mrequete, Mconnect);
                        updata.Parameters.Add(dbo.AjoutParametre("id", Odsdata.Tables[0].Rows[k][0], updata));
     
                        for (int j = 1; j < Odstschema.Tables[0].Rows.Count; j++)   //ajout des paramètres
                        {
                            updata.Parameters.Add(dbo.AjoutParametre("value" + j, Odsdata.Tables[0].Rows[k][j], updata));
                        }
     
                        dbo.ExecuteNonQuery(updata, Mconnect);
                        updata.Dispose();
     
     
                        Mdsdata.Dispose();
                        Mdsdata.Reset();
     
     
                    }

    De 10 minutes pour la 1ère table, je suis passé à une bonne minute. Par contre, pour la 3ème table, je tourne à 1 requête / seconde... Il n'y aurais pas moyen d'optimiser encore ce que j'ai fait ?

    Pour les ETL, j'avais déjà regardé Talend Open Studio. Malheureusement, il n'est pas possible d'avoir un schéma dynamique. Pour cet ETL, il doit connâitre à l'avance le schéma des tables, et vu que mes schémas sont tous différents, je devais pour chaque table Oracle, lui dire le schéma qu'il allait récupérer et lui indiquer dans quelle table MySql il devait aller. Cela ne posait pas vraiment de problèmes, le soucis était que si je rajoutais une table dans Oracle, je devais réouvrir Talend Open Studio afin de rajouter la nouvelle table... Il n'y avait pas moyen de faire une boucle pour traiter toutes les tables comme il doit connaitre le schéma à l'avance.

Discussions similaires

  1. Membre connecté ou non connecté
    Par drick35 dans le forum Langage
    Réponses: 2
    Dernier message: 20/09/2013, 09h54
  2. Choisir Mode connecté ou non connecté
    Par bazoga dans le forum Développement
    Réponses: 7
    Dernier message: 30/11/2011, 15h00
  3. Appli C# & ASP.NET en mode non-connecté
    Par lololo60 dans le forum C#
    Réponses: 6
    Dernier message: 02/12/2010, 11h39
  4. phpmyadmin ne lance pas en mode non connecté
    Par souadmaa dans le forum Ubuntu
    Réponses: 3
    Dernier message: 12/01/2010, 15h42
  5. [MySQL] Séparer les membres connectés et non connectés en 2 tableaux
    Par je_suis_tres_gentil dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 12/04/2009, 19h06

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