C#-mySQL Programme trop long à s'executer.

Résolu/Fermé
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022 - Modifié le 29 juil. 2022 à 20:50
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022 - 8 nov. 2022 à 11:37

Bonjour,

j'ai un soucis, avec mon programme. J'ai une application windowsform, toute simple, avec un bouton pour aller chercher un fichier , un bouton parcourir pour choisir un dossier de destination, pour créer un fichier excel en sortie et un bouton pour "lancer le traitement".
 

j'ai également mis une progressbar afin de voir le résultat., voici le principe de fonctionnement :

une fois mon fichier choisi, mon programme va parcourir chaque ligne du fichieret je souhaite recupérer le siren toutes les 14 lignes ( voir partie dans le code recupération des sirens).

Ceci fait, sur un fichier échantillon, j'ai bien tous les siren dans mon tableau.

Ensuite je vais parcourir mon tableau faire une requete qui va prendre pour condition sirens[a] et après je vais récupérer le résultats de la requete dans des variables, puis je constitut mon fichier excel.

Le problème : quand je choisi un fichire petit, avec moins de  500 lignes, ça marche, mais si j'en choisi un plus volumineux, mon programme tourne puis s'arrete et plus rien ne marche. Le soucis c'est qu'en production je vais avoir des fichires de 50 000 lignes.

J'ai fais la monté de version de visual studio 2022 mais ça n'a rien changé et j'utilise le framework .net 4.7.2.

 
    private void btn_start_ficExcel_Click(object sender, EventArgs e)
        {
            // Set Minimum to 1 represente la 1ere ligne
            mabarre.Visible = true;
            mabarre.Minimum = 1;
 
            string FileToRead = txtbox_entree.Text;
 
            /*
                RECUPERATION DES SIRENS
             */
 
            String[] lines2 = File.ReadAllLines(FileToRead);
            List<String> sirens = new List<String>();
            for (Int32 index = 2; index < lines2.Count(); index += 14)
            {
                if (lines2[index].Substring(0, 5) == "DT1DT")
                {
                    sirens.Add(lines2[index].Substring(6, 14));
 
                }
 
            }
            // Set Maximum  - correspond au nombre de ligne du fichier
            mabarre.Maximum = File.ReadAllLines(FileToRead).Length;
            // Set the initial value of the ProgressBar.
            mabarre.Value = 1;
            // Set the Step property - 1 chaque ligne lu
            //mabarre.Step = 1;
            /*
               Connexion à la base mysql
            */
            string server = "xxxxxxxxx";
            string database = "xxxxxx";
            string user = "xxxxxxx";
            string password = "xxxxxxxx";
            string port = "xxxxxxx";
 
            string connString = "Server=" + server + "; Port=" + port + ";Database=" + database + ";Uid=" + user + ";Pwd=" + password + ";SSL Mode=None;default command timeout=0";
            string marequete = "";
 
 
 
 
            conn = new MySqlConnection(connString);
            try
            {
                conn.Open();
            }
            catch (MySqlException erreur)
            {
                MessageBox.Show(erreur.ToString());
                conn.Close();
            }
 
 
            /*
           CREATION ET OUVERTURE DU FICHIER EXCEL
        */
            DateTime today = (DateTime.Now).AddMonths(-1);
            string d = Convert.ToString(today);
            string yyyy = d.Substring(6, 4);
            string mm = d.Substring(3, 2);
            string jour = d.Substring(0, 2);
            string heure = d.Substring(11, 2);
            string minute = d.Substring(14, 2);
            string seconde = d.Substring(17, 2);
 
            repexc = folderBrowserDialog2.SelectedPath + "\\mondossier" + yyyy + mm + jour + "_" + heure + minute + seconde + ".xlsx";
            Microsoft.Office.Interop.Excel.Application xla = new Microsoft.Office.Interop.Excel.Application();
            xla.Visible = false;
            Workbook wb = xla.Workbooks.Add(XlSheetType.xlWorksheet);
            //WorksheetCollection worksheets = xla.Worksheets;
            Worksheet ws = (Worksheet)xla.ActiveSheet;
            ws.Cells[1, 1] = "colonne 1";
            ws.Cells[1, 2] = "colonne 2"; 
            ws.Cells[1, 3] = "colonne 3";
			...............
			...............
			//je créé les différents entete
 
            UneCellule = ws.get_Range("A1", "M1");
            ws.Columns.Font.Name = "MS Sans Serif";
            ws.Columns.Font.Size = 12;
 
 
            string nomcol1 = "";
            string nomcol2 = "";
            string nomcol3 = "";
			........
			....... //je créé les différentes variables
 
 
            /*
                Parcours de la base de données et récupération du résultat
            */
 
			
            for (int a = 2; a < sirens.Count; a++) //
            {
 
                marequete=" select t0.tesccpcod, "+
               "t0.col1, "+
               "t0.col2, " +
               "t0.col3, " +
               "t0.xxxx, " +
               "t0.xxxx, " +
               "t1.xxxx," +
               "t2.xxxx," +
               "t2.xxxx," +
               "t2.xxxx," +
                "t1.xxxx," +
                "t1.xxxxx," +
                "t1.xxxx " +
                "from matable0 t0 " +
                 "INNER join matable1 t1 on t1.xxxx = t0.xxx " +
                 "inner join matable2 t2 on t2.xxxx = t0.xxxx " +
                 "inner join matable3 t3 on t3.xxxx = t0.xxxx " +
                 "inner join matable4 t4 on t4.xxxx = t0.xxxx " +
                 "where t0.num ='" + sirens[a] + "'";
 
                MySqlCommand cmd = new MySqlCommand(marequete, conn);
                  monreader = cmd.ExecuteReader();
 
                if (monreader.Read())
                {
                    nomcol1 = monreader.GetString(0);
                    nomcol2 = monreader.GetInt64(1).ToString();
                    nomcol3 = monreader.GetString(2);
                   ........ //jusque là pas de soucis je recupère mon résultat
 
 
                    //je rempli mon tableau pour rempli le fichier excel
                    ws.Cells[a, 1] = nomcol1;
                    ws.Cells[a, 2] = nomcol2;
					...............
 
 
                }
                else
                {
                    ws.Cells[a, 2] = sirens[a];//si ko, dans mon fichier excel je ne met que l'identifiant
 
                }
                   mabarre.PerformStep(); //je rempli ma barre
                   monreader.Close();
 
            }//fin du for
                
 
			
			
            ws.SaveAs(repexc, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
            xla.Quit();
 
        }
 
 
 
    }//fin méthode

comment ça se fait que le logiciel plante si c'est des fichiers plus lourds ?

N'y a t-il pas moyen d'optimiser mon code pour le rendre plus efficace et est ce que je m'y prend bien dans ma façon de requéter?
merci à vous.
 


Windows / Chrome 103.0.0.0

25 réponses

Utilisateur anonyme
22 juil. 2022 à 13:44

Bonjour

tout d'abord, il y a un bug en cours sur le site avec la coloration en C#. Du coup, j'ai modifié ton message pour forcer la coloration C++ afin que cela soit plus lisible.

Pour ton problème, il y a une accumulation de "petites" choses qui misent bout à bout son consommatrices de temps et de ressources (et par effet de bord, la gestion des ressources utilisées en excès fait perdre du temps)

Tu lis plusieurs fois le fichier:

  1. à la ligne 14,
  2. à la ligne 26, alors que tu connais déjà le nombre de lignes avec la taille du tableau lines2

Donc 2 fois 500 lignes, ça ne fait que 1000 lignes, alors que 2 fois 50 000, ça en fait 100 000.

En plus ce n'est pas cohérent, puisse qu'ensuite tu inclémentes ta barre de progression à chaque fois qu'un "siren" est exporté dans excel, donc tu maximum devrais être le nombre d'items dans la List siren

Tu utilises l'api office:

c'est très très lent car l'api lance Excel et lui donne des instructions, qu'Excel exécute, l'api attend le retour d'Excel pour te donner la main etc... Il existe plein de façons de faire sans office https://lite.qwant.com/?q=C%23+write+data+xlsx+without+excel&client=opensearch

Tu peux vérifier l'influence de cette partie (sans rien changer au reste) en écrivant un fichier texte à la place d'Excel et en comparant les temps d'exécution.

A mon avis, c'est le post le plus chronophage.

Tu fais des action inutiles

  1. A la ligne 6, le minimum de la barre de progression ne change pas d'un fichier à l'autre, donc il faut le figer une fois pour tout dans les propriétés de la barre en mode design
  2. de la ligne 61 à 68, tu réinventes la roue, un objet DateTime, d'une part te donne directement ses différentes "valeurs" (aves ses propriétés Day, Month, Year, Hour, Minute, Second etc...) mais surtout sait directement exporter un texte formaté 
    DateTime.Now.ToString("yyyyMMdd_HHmmss")

Tu atteints peut-être un niveau critique de ressources

Tu lis les 50 000 lignes d'un coup, ça charge peut-être un peu trop ta RAM.

Plutôt que le lire entier, lis le ligne par ligne. Pour ça, il faut utiliser un streamReader.

Tu fais une boucle tant le le fichier n'est pas arrivé à la fin, dans cette boucle

  1. tu lignes 13 lignes, (tu peux faire une seconde boucle mais paradoxalement, ça va généralement plus vite à l'exécution de faire 13 instructions à la suite)
  2. tu lis la ligne que tu utilises
  3. Penses à incrémenter un compteur pour connaitre le maximum de ta barre de progression

1
Utilisateur anonyme
27 juil. 2022 à 21:24

Dernière étape, si et seulement si les précédentes se sont bien passées : le peuplement des "Societe" par la BDD

Je ne peux pas tester, car je n'ai ni ta BDD ni les bibliothèques associées

Dans la partie Méthodes statiques, tu ajoutes

        /// <summary>
        /// Recherche de chaque société et import des infos qui la concerne
        /// </summary>
        public static void PeuplerListeSocieteParBDD(List<Societe> Societes)
        {
            MonLog("========================");
            MonLog($"Début peuplement BDD à {DateTime.Now:HH-mm-ss.fff}");

            MySqlConnection conn;
            MySqlDataReader monreader = null;
            string server = "server";
            string database = "mabse";
            string user = "monuser";
            string password = "monpass";
            string port = "2222";

            string connString = $"Server={server}; Port={port};Database={database};Uid={user};Pwd={password};SSL Mode=None;default command timeout=0";
            string marequete = "";

            conn = new MySqlConnection(connString);
            try
            {
                conn.Open();



                foreach(Societe s in Societes)
                {
                    MonLog($"Siren à chercher {s.Siren}");

                    marequete = " select t0.tesccpcod, " +
                   "t0.numero, " +
                   "t0.identifiant, " +
                   "t0.xxxxx, " +
                   "t0.xxxxx, " +
                   "t0.xxxxx, " +
                   "t1.xxxxx," +
                   "t2.xxxxx," +
                   "t2.xxxxxx," +
                   "t2.xxxxxx," +
                    "t1.xxxxxx," +
                    "t1.xxxxxx," +
                    "t1.xxxxxx " +
                    "from tes000pf t0 " +
                     "left join tes001pf t1 on t1.ccccc = t0.ccccc " +
                     "left join tes002pf t2 on t2.ccccc = t0.ccccc " +
                     "left join tes003pf t3 on t3.ccccc = t0.ccccc " +
                     "left join tes004pf t4 on t4.ccccc = t0.ccccc " +
                     "where t0.numero ='" + s.Siren + "'";

                    MonLog("Ma requete utilisé:" + marequete);
                    MonLog("sirens :" + s.Siren);

                    MySqlCommand cmd = new MySqlCommand(marequete, conn);
                    monreader = cmd.ExecuteReader();
                    if (monreader.Read())  //while
                    {
                        //recuperation des données
                        s.Numcode = monreader.GetString(0);
                        s.Matadh = monreader.GetString(1);
                        s.Solmon = monreader.GetString(2);
                        s.Soldat = monreader.GetString(3);
                        s.Adhfer = monreader.GetString(4);
                        s.Raison = monreader.GetString(5);
                        s.Milib = monreader.GetString(6);
                        s.Emibas = monreader.GetString(7);
                        s.Emicoe = monreader.GetString(8);
                        s.Debdat = monreader.GetString(9);
                        s.Findat = monreader.GetString(10);
                        s.Datrec = monreader.GetString(11);

                        monreader.Close();
                    }
                }//fin du for

                MonLog("********* FIn de la boucle - sauvegarde du fichier excel ********** ");
            }
            catch (MySqlException erreur)
            {
                MonLog("******** ERREUR DANS LE TRAITEMENT :" + erreur.ToString());

                conn.Close();
            }
            catch (Exception e)
            {
                MonLog("=========Erreur===============");
                MonLog(e.StackTrace);
                MonLog("=========Fin Erreur===============");
            }


            MonLog($"Fin peuplement BDD à {DateTime.Now:HH-mm-ss.fff}");
            MonLog("========================");
        }

Et dans le formulaire

            List<Societe> societes = Societe.InitFromFichierSiren("FICHIER-anonyme.txt");
            Societe.PeuplerListeSocieteParBDD(societes);
            Societe.ExportListeSocieteToExcel(societes, "FICHIER-anonyme.xlsx");

1
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
25 juil. 2022 à 14:41

Bonjour,

merci pour tes conseils, j'ai commencé à optimiser un peu tout ça mais j'ai du mal à trouver autre chose, pour générer mon fichier excel, je vais essayer de creuser la chose.
Je tente de le faire avec Oledb mais j'ai du mal à saisir le concept.

0
Utilisateur anonyme
25 juil. 2022 à 15:28

Oledb c'est un "vieux" moteur de base de données.

Mais Excel est compatible.

Sinon, si tu as l'habitude de Linq, le NuGet Linq to xls est pas mal.


0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
26 juil. 2022 à 14:50

Bonjour,

pour répondre à ta question, je ne connais pas trop linq, ni le nuget, cela fait longtemps que je n'est plus fait de c#. Je fais des programmes pour dépanner, mais à l'orgine quand j'ai bossé, j'ai juste repris quelques programme que j'ai améliorer, mais j'ai pas fais de gros développement ...:(

0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
Modifié le 26 juil. 2022 à 16:12

Bonjour,

j'ai modifié mon code,  en esperant que ça puisse changer quelque chose, avec ce que j'ai appris recemment.

J'ai créé des liststring et j'ai enregistré les valeurs que j'ai récupéré dans chacune des variables, voici comment j'ai procédé : 

namespace Suivi_tese
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
         

        }

        private FolderBrowserDialog folderBrowserDialog2;
       
        private bool selfichier;
        private bool selrepertoire;
        private static string repexc = "";

        private static MySqlConnection conn;
        private static MySqlDataReader monreader = null;
        protected Range Cellules;
        protected Range UneCellule;

        List<string> numcode = new List<string>();
        List<string> matadh = new List<string>();
        List<string> solmon = new List<string>();

        List<string> soldat = new List<string>();
        List<string> adhfer = new List<string>();
        List<string> raison = new List<string>();
        List<string> milib = new List<string>();
        List<string> emibas = new List<string>();
        List<string> emicoe = new List<string>();

        List<string> debdat = new List<string>();
        List<string> findat = new List<string>();
        List<string> datrec = new List<string>();

        public  string ReturnReaderValue(MySqlDataReader reader, int indexe)
        {
            if (!reader.IsDBNull(indexe))
            {
               return reader.GetString(indexe);
            }
            else
            {
                return "";
            }           
        }
        private void btn_start_ficExcel_Click_1(object sender, EventArgs e)
        {
            BasicConfigurator.Configure();

            string path = @"C:\Users\.........\test\log.txt";
            log.Info("--------------------");
            log.Info("Debut de traitement");
            log.Info("--------------------");

            log.Info("Chemin du fichier pour le log " + path);


            if (selrepertoire == true & selfichier == true)
            {
                log.Info("Selection OK");
                int compteur = 0;
                // LBLRES.Text = compteur.ToString();

                // Set Minimum to 1 represente la 1ere ligne
                mabarre.Visible = true;
               

                string FileToRead = txtbox_entree.Text;
                log.Info("Fichier dub choisi" + txtbox_entree.Text);


                /*
                    RECUPERATION DES SIRENS
                 */
                #region Recuperation_sirens
                int moncompteur = 0;
                String[] lines2 = File.ReadAllLines(FileToRead);
                List<String> sirens = new List<String>();
                for (Int32 index = 2; index < lines2.Count(); index += 14)
                {
                    if (lines2[index].Substring(0, 5) == "Info1")
                    {
                        sirens.Add(lines2[index].Substring(6, 14));
                        moncompteur++;
                    }

                }
                log.Info("Mon compteur :" + moncompteur);
                // Set Maximum  - correspond au nombre de ligne du fichier
                mabarre.Maximum = sirens.Count;
                // Set the initial value of the ProgressBar.
                mabarre.Value = 1;

                #endregion

                /*
                   Connexion à la base mysql
                */
                string server = "server";
                string database = "mabse";
                string user = "monuser";
                string password = "monpass";
                string port = "2222";

                string connString = "Server=" + server + "; Port=" + port + ";Database=" + database + ";Uid=" + user + ";Pwd=" + password + ";SSL Mode=None;default command timeout=0";
                string marequete = "";

                conn = new MySqlConnection(connString);
                try
                {
                    conn.Open();

                    /*
                      CREATION ET OUVERTURE DU FICHIER EXCEL
                   */
                    repexc = folderBrowserDialog2.SelectedPath + "\\dossier" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".xlsx";
                    Microsoft.Office.Interop.Excel.Application xla = new Microsoft.Office.Interop.Excel.Application();
                    xla.Visible = false;
                    Workbook wb = xla.Workbooks.Add(XlSheetType.xlWorksheet);
                    //WorksheetCollection worksheets = xla.Worksheets;
                    Worksheet ws = (Worksheet)xla.ActiveSheet;

                    ws.Cells[1, 1] = "colonne 1";
                    ws.Cells[1, 2] = " colonne  2";
                    ws.Cells[1, 3] = " colonne  3";
                    ws.Cells[1, 4] = " colonne  4";
                    ws.Cells[1, 5] = "colonne 5";
                    ws.Cells[1, 6] = "colonne 6";
                    ws.Cells[1, 7] = "colonne 7";
                    ws.Cells[1, 8] = "colonne 8";
                    ws.Cells[1, 9] = "colonne 9";
                    ws.Cells[1, 10] = "colonne 10";
                    ws.Cells[1, 11] = "colonne 11";
                    ws.Cells[1, 12] = "colonne 12";
                    ws.Cells[1, 13] = "colonne 13";
                    UneCellule = ws.get_Range("A1", "M1");
                    ws.Columns.Font.Name = "MS Sans Serif";
                    ws.Columns.Font.Size = 12;


                    int cptCol = 2;
                    /*
                        Parcours de la base de données et récupération du résultat
                    */

                    int compteurAnnexe = 0;

                    for (int a = 0; a < sirens.Count; a++)
                    {

                        marequete = " select t0.tesccpcod, " +
                       "t0.numero, " +
                       "t0.identifiant, " +
                       "t0.xxxxx, " +
                       "t0.xxxxx, " +
                       "t0.xxxxx, " +
                       "t1.xxxxx," +
                       "t2.xxxxx," +
                       "t2.xxxxxx," +
                       "t2.xxxxxx," +
                        "t1.xxxxxx," +
                        "t1.xxxxxx," +
                        "t1.xxxxxx " +
                        "from tes000pf t0 " +
                         "left join tes001pf t1 on t1.ccccc = t0.ccccc " +
                         "left join tes002pf t2 on t2.ccccc = t0.ccccc " +
                         "left join tes003pf t3 on t3.ccccc = t0.ccccc " +
                         "left join tes004pf t4 on t4.ccccc = t0.ccccc " +
                         "where t0.numero ='" + sirens[a] + "'";

                        log.Info("Ma requete utilisé:" + marequete);
                        log.Info("sirens :" + sirens[a]);

                        MySqlCommand cmd = new MySqlCommand(marequete, conn);
                        monreader = cmd.ExecuteReader();             
                        if (monreader.Read())  //while
                        {
							//recuperation des données
                            numcode.Add(ReturnReaderValue(monreader, 0));    //code
                            matadh.Add(ReturnReaderValue(monreader, 1));    //siret
                            solmon.Add(ReturnReaderValue(monreader, 2));   // matadh                           
                            soldat.Add(ReturnReaderValue(monreader, 3));
                            adhfer.Add(ReturnReaderValue(monreader, 4));
                            raison.Add(ReturnReaderValue(monreader, 5));
                            milib.Add(ReturnReaderValue(monreader, 6));
                            emibas.Add(ReturnReaderValue(monreader, 7));
                            emicoe.Add(ReturnReaderValue(monreader, 8));
                            debdat.Add(ReturnReaderValue(monreader, 9));
                            findat.Add(ReturnReaderValue(monreader, 10));
                            datrec.Add(ReturnReaderValue(monreader, 11));

							//enregistrement dans mon fichier excel
                            ws.Cells[cptCol, 1] = numcode[compteurAnnexe];
                            ws.Cells[cptCol, 2] = matadh[compteurAnnexe];
                            ws.Cells[cptCol, 3] = solmon[compteurAnnexe];
                            ws.Cells[cptCol, 4] = soldat[compteurAnnexe];
                            ws.Cells[cptCol, 5] = adhfer[compteurAnnexe];
                            ws.Cells[cptCol, 6] = raison[compteurAnnexe];
                            ws.Cells[cptCol, 7] = milib[compteurAnnexe];
                            ws.Cells[cptCol, 8] = emibas[compteurAnnexe];
                            ws.Cells[cptCol, 9] = emicoe[compteurAnnexe];
                            ws.Cells[cptCol, 10] = debdat[compteurAnnexe];
                            ws.Cells[cptCol, 11] = findat[compteurAnnexe];
                            ws.Cells[cptCol, 12] = datrec[compteurAnnexe];

                            compteurAnnexe++;
                            cptCol++;
                            mabarre.PerformStep();

                        }
                        else
                        {
                            ws.Cells[cptCol, 2] = sirens[a];
                            cptCol++;
                        }

                        mabarre.PerformStep();
                        monreader.Close();

                        compteur++;
                        LBLRES.Text = compteur.ToString();

                    }//fin du for

                    log.Info("********* FIn de la boucle - sauvegarde du fichier excel ********** " );
                    ws.SaveAs(repexc, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                    xla.Quit();


                    MessageBox.Show("Fin du traitement", "Message d'information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch (MySqlException erreur)
                {
                    log.Info("******** ERREUR DANS LE TRAITEMENT :" + erreur.ToString());
                    MessageBox.Show(erreur.ToString());

                    conn.Close();
                }
                log.Info("-----------  FIN DE TRAITEMENT -----------");
            }
            else
            {
                log.Info("Fin du traitement du traitement - KO ");


                log.Error("AUcun Fichier ou dossier selectoinné");
                MessageBox.Show("Merci de choisir un fichier et un répretoire de sortie", "Message d'information", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
          //  monstream.Close();
        }
    }//fin méthode public parital class



}//fin du namespace

mais quand j'ai des petits fichiers, ça marche, mais quand il est plus lours ( environ 50k de ligne) le fichier en entrée, le programme bug, d'après mon log, il s'arrete puis il ne fait plus rien, c'est agaçant.

J'avais un programme que j'ai récupéré pour y faire deux trois modification, même lui fonctionné, on devait attendre un moment puis il reparté mais là il ne me fait rien, comment ça se fait?

Pourtant j'ai 16go de ram et presque 1to dans mon disque dur,.

merci

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
Modifié le 26 juil. 2022 à 16:13

Je pensais à une chose, avec le code suivant :

       /*
                    RECUPERATION DES SIRENS
                 */
                #region Recuperation_sirens
                int moncompteur = 0;
                String[] lines2 = File.ReadAllLines(FileToRead);
                List<String> sirens = new List<String>();
                for (Int32 index = 2; index < lines2.Count(); index += 14)
                {
                    if (lines2[index].Substring(0, 5) == "Info1")
                    {
                        sirens.Add(lines2[index].Substring(6, 14));
                        moncompteur++;
                    }

                }

meme si mon fichier en entrée est volumineux, ce code récupère chaque siren dans un tableau, donc par exemple, pour un fichier avec 1000 lignes, je peux n'avoir que 50 ou 100 sirens, ce qui est negligeable, mais là mon programme tourne puis il s'arrete sans raison et je n'ai pas d'indication dans mes logs.

Merci

0
Utilisateur anonyme
26 juil. 2022 à 18:17

Tout d'abord, il ne faut pas utiliser 12 listes de string, mais une seule liste d'une classe que tu auras écrites dont les propriétés sont au moins les 12 paramètres dont tu as besoin.

Mais ça c'est si et seulement si tu as besoin des ces données ailleurs dans le programme.

Dans ce que tu montres, les listes ne servent à rien à part charger encore plus la RAM inutilement.

Dans ton précédent code, tu avais ça 

                    nomcol1 = monreader.GetString(0);
                    nomcol2 = monreader.GetInt64(1).ToString();
                    nomcol3 = monreader.GetString(2);
                   ........ //jusque là pas de soucis je recupère mon résultat
 
 
                    //je rempli mon tableau pour rempli le fichier excel
                    ws.Cells[a, 1] = nomcol1;
                    ws.Cells[a, 2] = nomcol2;
					...............

Donc 12 strings qui été réutilisées à chaque boucle, ce qui est une utilisation faible de la RAM.

Pour utiliser encore un peu moins de RAM tu aurais pu faire ça

                    //je rempli mon tableau pour rempli le fichier excel
                    ws.Cells[a, 1] = monreader.GetString(0);
                    ws.Cells[a, 2] = monreader.GetInt64(1).ToString();
					...............

Et donc coup, cela tend à faire penser que tu n'as pas besoin de ces données plus loin dans ton programmes.

Et maintenant, non seulement tu stockes toutes tes valeurs dans des listes (ce qui à chaque nouvelle valeur consomme de plus en plus de RAM), mais au lieu de lire dans le reader tu fais appel à une méthode, donc des appels supplémentaires ce qui est consommateur de temps et d'un peu de mémoire. 

Quand on cherche à en gagner, on n'en rajoute pas inutilement.


Concernant 

mais là mon programme tourne puis il s'arrete sans raison et je n'ai pas d'indication dans mes logs.

s'il n'y a rien dans les logs concernant la progression de l'import (puis que le code correspondant à ce texte est celui de l'import) c'est d'abord parce que tu n'y loggues rien.

Tu peux essayer ça

if (lines2[index].Substring(0, 5) == "Info1")
{
    sirens.Add(lines2[index].Substring(6, 14));
    moncompteur++;
    log.Info(string.Format("Ligne n°{0} importée, son contenu est '{1}'", index, lines2[index]);
}

Note l'utilisation de string.Format qui est beaucoup plus pratique pour construire des string que la concaténation (si tu codes avec VS 2019 ou 2022, il y a une version encore plus simple)

En plus, il n'y a qu'un seul try catch, plus tard et ce try catch ne gère qu'un seul type d'erreurs, il suffit de n'importe quelle autre pour que ça plante sans log et potentiellement sans message d'erreur.

D'ailleurs, les logs normalement ça sert en production pas pendant le développement, sauf sur du temps réel mais là ce n'est pas le cas.

Laisse le programme en débug planter pour pouvoir débogger.

 Enfin

Pourtant j'ai 16go de ram et presque 1to dans mon disque dur,.

Oui mais c'est windows qui choisit combien de RAM et de Swap seront disponibles pour ton programme et ça ne sera qu'une infime partie de tout ça.


0
Utilisateur anonyme
26 juil. 2022 à 18:21

PS 1, la coloration en C# ne fonctionne plus, merci de sélectionner C++, c'est compatible à 95% au moins, ce sera plus simple à lire.

PS 2, peux tu constituer un fichier exemple d'une 50 lignes anonymisées mais vraiment représentatives (si une données fait 6 chiffres, il faut qu'il y en ait 6 etc...) et le mettre en ligne sur cjoint ou équivalent et poster le lien ici?

1
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
27 juil. 2022 à 09:02

BOnjour,

j'ai fais une copie d'écran du processus, quand j'execute le programme, au début il tourne normalement, mais après plus rien :

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
27 juil. 2022 à 09:09

J'ai mis en pièce jointe via ce lien, c'est un fichier au format txt : 

https://www.cjoint.com/c/LGBheirWdWI

C'est bien vu au niveau des try, je vais tenter d'en mettre pour ovir ce qu'il se passe également.

Pour ce qui est des logs, je m'en sert pour avoir une trace du traitement, comme ça une fois le programme en production, je vais juste modifier le chemin du dossier et on aura toujours une trace.

Pour exemple, le fichire ci joint possede 126 lignes, dans ce fichire je récupère que 9 sirens. J'ai tenté avec un fichier de production, qui fait environ 5824 lignes, il y a 32 sirens ( de mémoire) dont normalement ce n'est pas grand chose.

J'ai connu des programmes qui faisait plus d'opération mais qui s'executé jusqu'au bout, mais lui.... c'est un mystère, pour l'instant.

Au fait, j'ai un peu surestimé le nombre de ligne des fichires, ce ne sont pas des fichires avec 50k de lignes mais plutot entre 5000 et 6000 lignes, dont ça devrait normalement pouvoir le faire.


Merci

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
27 juil. 2022 à 11:09

J'ai ce genre de message qui revient continuellement, quand j'utilise un fichier de 5000 lignes. Il dit que le thread s'est arreté, j'ai l'impression qu'il a stoppé le traitement en plein milieu, je ne sais pas pourquoi.

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
27 juil. 2022 à 11:43

J'ai debogué pas a pas et j'ai remarqué une chose , est ce que je m'y prend bien ?

Car dans ma boucle for, j'ai ceci à la fin :

monreader.close()

monreader.dispose();

et c'est à partir de là que le programme cesse de tourner , quand mon compteut a=4, c'est etrange.

0
Utilisateur anonyme
27 juil. 2022 à 16:26

En commençant par la fin, la ligne où tu fermes le reader, ne me parait pas problématique puisque tu le réalimentes à chaque itération. Mais je n'en suis pas certain je n'utilise que très rarement des bases de données et mon dernier projet avec un reader a plus de 15 ans...

Le thread qui s'arrête régulièrement n'est pas le tien, ça peut par exemple être les appels à la base de données que le reader exécute.

Pour le reste, je tacherais de trouver un moment dans la soirée pour faire un test.

Là je suis dans les transports en commun, je vais tacher de jeter un œil au fichier 


0
Utilisateur anonyme
27 juil. 2022 à 18:23

Le fichier que tu as fourni n'est pas lu pas ton code.

Il y a ça

if (lines2[index].Substring(0, 5) == "Info1")
{
    sirens.Add(lines2[index].Substring(6, 14));

Si je regarde la 3eme ligne du fichier, elle ne commence pas par Info1, par contre, il y a un nombre de 14 chiffres à l'index 6.

A l'inverse la première ligne, commence par Informations1, mais les 14 caractères à partir de l'index 6 sont 

"ation1        "

Pour la suite de mon test, je vais partir du principe, que la ligne ne commence pas par "Info1". 


0
Utilisateur anonyme
27 juil. 2022 à 19:10

Procédons par étapes.


D'abord, je n'ai pas ta base de données, donc c'est une partie que je ne peux pas tester. 

Du coup, je vais remplir les "Sociétés" par des suites de 10 caractères. Chaque suite sera unique pour une "cellule" du fichier de sortie.

Dans un premier temps, on va exporter un csv.

Dans ton projet, tu vas ajouter une classe nommée Societe.

Dans le fichier Societe.cs tu vas mettre ce code

    class Societe
    {
        //Chaque propriété est une information utile ultérieurement
        public string Siren { get; set; }
        public string Numcode { get; set; }
        public string Matadh { get; set; }
        public string Solmon { get; set; }

        public string Soldat { get; set; }
        public string Adhfer { get; set; }
        public string Raison { get; set; }
        public string Milib { get; set; }
        public string Emibas { get; set; }
        public string Emicoe { get; set; }

        public string Debdat { get; set; }
        public string Findat { get; set; }
        public string Datrec { get; set; }

        #region Méhodes de classe
        /// <summary>
        /// Retourne cette instance sous la forme d'une string compilée en ligne de csv
        /// </summary>
        /// <returns></returns>
        public string ToCsv()
        {
            return $"{Numcode};{Matadh};{Solmon};{Soldat};{Adhfer};{Raison};{Milib};{Emibas};{Emicoe};{Debdat};{Findat};{Datrec}";
        }


        #endregion

        #region Méthodes statiques
        /// <summary>
        /// Importe le fichier Siren et initie la liste de societés
        /// </summary>
        /// <param name="Filename"></param>
        /// <returns></returns>
        public static List<Societe> InitFromFichierSiren(string Filename)
        {
            MonLog("========================");
            MonLog($"Début import Sirens à {DateTime.Now:HH-mm-ss.fff}");
            List<Societe> res = new List<Societe>();

            try
            {
                string[] lignes = File.ReadAllLines(Filename);

                for (int i = 2; i < lignes.Count(); i += 14)
                {
                    string siren = lignes[i].Substring(6, 14);
                    res.Add(new Societe { Siren = siren });
                    MonLog($"Ligne n°{i} inmportée, siren : {siren}");
                }
            }
            catch (Exception e)
            {
                MonLog("=========Erreur===============");
                MonLog(e.StackTrace);
                MonLog("=========Fin Erreur===============");
            }

            MonLog($"Fin import Sirens à {DateTime.Now:HH-mm-ss.fff}");
            MonLog("========================");

            return res;
        }

        /// <summary>
        /// Permet de logguer dans le fichier en mode Realease et dans la console en mode Debug
        /// </summary>
        /// <param name="Texte"></param>
        private static void MonLog(string Texte)
        {
#if DEBUG
            Console.WriteLine(Texte);
#else
            log.Info(Texte);
#endif
        }

#if DEBUG
        /// <summary>
        /// Comme je n'ai pas ta base de données me permet de mettre des datas dans la liste de societé
        /// De ton coté, ça permettra un premier test d'export Excel sans accès à la bdd
        /// </summary>
        /// <param name="Societes"></param>
        public static void DebugPeuplerListeSocietesSansBdd(List<Societe> Societes)
        {
            MonLog("========================");
            MonLog("Début peuplement débug");
            int i = 64;
            foreach (Societe s in Societes)
            {
                s.Adhfer = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Datrec = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Debdat = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Emibas = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Emicoe = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Findat = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Matadh = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Milib = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Numcode = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Raison = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Soldat = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                s.Solmon = new string(Convert.ToChar(i++), 10); //10 fois le caractère i;
                MonLog($"Peuplement {s.ToCsv()}");
                i++;
                if (i == 127)
                    i = 64;
            }

            MonLog("Fin peuplement débug");
            MonLog("========================");
        }
#endif
        /// <summary>
        /// Exporte les datas dans un fichiers csv
        /// </summary>
        /// <param name="Societes"></param>
        /// <param name="FileName"></param>
        public static void ExportListeSocieteToCsv(List<Societe> Societes, string FileName)
        {
            MonLog("========================");
            MonLog($"Début export CSV à {DateTime.Now:HH-mm-ss.fff}");

            List<string> res = new List<string> { "colonne 1;colonne 2;colonne 3;colonne 4;colonne 5;colonne 6;colonne 7;colonne 8;colonne 9;colonne 10;colonne 11;colonne 12;colonne 13" };
            res.AddRange(Societes.Select(s => s.ToCsv()));
            File.WriteAllLines(FileName, res);

            MonLog($"Fin export CSV à {DateTime.Now:HH-mm-ss.fff}");
            MonLog("========================");
        }
        #endregion
    }

Dans ton formulaire, tu pourras tester ce code de cette façon

            List<Societe> societes = Societe.InitFromFichierSiren("FICHIER-anonyme.txt");
            Societe.DebugPeuplerListeSocietesSansBdd(societes);
            Societe.ExportListeSocieteToCsv(societes, "FICHIER-anonyme.csv");

Note, j'ai écrit une méthode qui "choisit" de logguer dans le fichier ou la console selon que tu sois en mode Realease ou Debug, l'avantage de la console c'est qu'on voit en live ce qui se passe.

Pour mon test ça donne

========================
Début import Sirens à 19-08-05.306
Ligne n°2 inmportée, siren : 08755006600029
Ligne n°16 inmportée, siren : 30168546980011
Ligne n°30 inmportée, siren : 30653515478983
Ligne n°44 inmportée, siren : 31189866415003
Ligne n°58 inmportée, siren : 31145294300014
Ligne n°72 inmportée, siren : 31441251105477
Ligne n°86 inmportée, siren : 31490147500002
Ligne n°100 inmportée, siren : 47584529000013
Ligne n°114 inmportée, siren : 31825157578539
Fin import Sirens à 19-08-05.354
========================
========================
Début peuplement débug
Peuplement HHHHHHHHHH;FFFFFFFFFF;KKKKKKKKKK;JJJJJJJJJJ;@@@@@@@@@@;IIIIIIIIII;GGGGGGGGGG;CCCCCCCCCC;DDDDDDDDDD;BBBBBBBBBB;EEEEEEEEEE;AAAAAAAAAA
Peuplement UUUUUUUUUU;SSSSSSSSSS;XXXXXXXXXX;WWWWWWWWWW;MMMMMMMMMM;VVVVVVVVVV;TTTTTTTTTT;PPPPPPPPPP;QQQQQQQQQQ;OOOOOOOOOO;RRRRRRRRRR;NNNNNNNNNN
Peuplement bbbbbbbbbb;``````````;eeeeeeeeee;dddddddddd;ZZZZZZZZZZ;cccccccccc;aaaaaaaaaa;]]]]]]]]]];^^^^^^^^^^;\\\\\\\\\\;__________;[[[[[[[[[[
Peuplement oooooooooo;mmmmmmmmmm;rrrrrrrrrr;qqqqqqqqqq;gggggggggg;pppppppppp;nnnnnnnnnn;jjjjjjjjjj;kkkkkkkkkk;iiiiiiiiii;llllllllll;hhhhhhhhhh
Peuplement ||||||||||;zzzzzzzzzz;;~~~~~~~~~~;tttttttttt;}}}}}}}}}};{{{{{{{{{{;wwwwwwwwww;xxxxxxxxxx;vvvvvvvvvv;yyyyyyyyyy;uuuuuuuuuu
Peuplement ??????????;??????????;??????????;??????????;;??????????;??????????;??????????;??????????;??????????;??????????;??????????
Peuplement ??????????;??????????;??????????;??????????;??????????;??????????;??????????;??????????;??????????;;??????????;
Peuplement ££££££££££;¡¡¡¡¡¡¡¡¡¡;¦¦¦¦¦¦¦¦¦¦;¥¥¥¥¥¥¥¥¥¥;??????????;¤¤¤¤¤¤¤¤¤¤;¢¢¢¢¢¢¢¢¢¢;??????????;??????????;;          ;??????????
Peuplement °°°°°°°°°°;®®®®®®®®®®;³³³³³³³³³³;²²²²²²²²²²;¨¨¨¨¨¨¨¨¨¨;±±±±±±±±±±;¯¯¯¯¯¯¯¯¯¯;««««««««««;¬¬¬¬¬¬¬¬¬¬;ªªªªªªªªªª;­­­­­­­­­­;©©©©©©©©©©
Fin peuplement débug
========================
========================
Début export CSV à 19-08-05.354
Fin export CSV à 19-08-05.371
========================

Et un fichier CSV parfaitement exploitable sous Excel


0
Utilisateur anonyme
27 juil. 2022 à 19:13

Fais ce même test de ton coté, sur un gros fichier.

Et s'il fonctionne note le temps d'exécution

0
Utilisateur anonyme
27 juil. 2022 à 19:56

2eme étape, seulement si la précédente s'est bien passée.

Tu vas aller dans la gestion des packages NuGet

Tu recherches MiniExcel et tu l'installe (je m'étais trompé Lind To Excel, c'est pour lire les fichiers xlsx)


0
Utilisateur anonyme
27 juil. 2022 à 19:59

Ensuite dans la classe, à la région Méthodes de classe tu ajoutes

        /// <summary>
        /// Retourne un dictionnaire compatible de MiniExcel
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, object> ToMiniExcel()
        {
            Dictionary<string, object> res = new Dictionary<string, object>();
            res.Add("Colonne 1", Numcode);
            res.Add("Colonne 2", Matadh);
            res.Add("Colonne 3", Solmon);
            res.Add("Colonne 4", Soldat);
            res.Add("Colonne 5", Adhfer);
            res.Add("Colonne 6", Raison);
            res.Add("Colonne 7", Milib);
            res.Add("Colonne 8", Emibas);
            res.Add("Colonne 9", Emicoe);
            res.Add("Colonne 10", Debdat);
            res.Add("Colonne 11", Findat);
            res.Add("Colonne 12", Datrec);
            return res;
        }

Et à la région Méthodes statiques tu ajoutes

        /// <summary>
        /// Exporte les datas dans un fichier xlsx
        /// </summary>
        /// <param name="Societes"></param>
        /// <param name="FileName"></param>
        public static void ExportListeSocieteToExcel(List<Societe> Societes, string FileName)
        {
            MonLog("========================");
            MonLog($"Début export Excel à {DateTime.Now:HH-mm-ss.fff}");

            List<Dictionary<string, object>> res = new List<Dictionary<string, object>>();

            res.AddRange(Societes.Select(s => s.ToMiniExcel()));

            if (File.Exists(FileName))
                File.Delete(FileName);

            MiniExcel.SaveAs(FileName, res);
 
            MonLog($"Fin export Excel à {DateTime.Now:HH-mm-ss.fff}");
            MonLog("========================");
        }

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
29 juil. 2022 à 07:43

Bonjour,

merci pour ton retour.

Je vais regarder tout ça  à tete reposer et teser cela :)

en parallèle, j'avais trouvé la raison pourquoi  le programme ne tournait pas..... dans ma base phpmyadmin il n'y avait pas de clé primaire.

Lorsque m'on collegue à fait l'export de la base ( de l'as400 vers mysql) il n'a pris que les données brut, quand j'ai découvert cela, j'ai créé les clefs primaires et je suis en train de tester les jointures, mais comme je reprend des données de plusieurs tables, plus je met de jointure, plus mon programme est lent. 

Je vais tester cela et je reviens vers toi, merci beaucoup :)

0
yg_be Messages postés 23392 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 décembre 2024 1 556
30 juil. 2022 à 09:36

Je pense que les données brut exportées de la base ( de l'as400 vers mysql) ne permettent pas d'exploiter les données.  Je crains qu'il manque les liens entre les tables.  A moins qu'il n'y ait dans les données brutes des champs que tu n'as pas remarqué et qui pourraient être utilisés comme lien.

Tu ne donnes pas assez d'information pour que je puisse être plus précis ou donner un exemple de ce qui manque.

Quel logiciel de bases de données était utilisé dans l'AS400?

0
Utilisateur anonyme
29 juil. 2022 à 07:55

De rien.

Je suis en congés quelques temps, et je n'aurais pas accès à un IDE.

Je pourrais répondre à des questions simples mais pas plus.


0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
29 juil. 2022 à 10:30

merci c'est super gentil :) 

0
ptisephy Messages postés 74 Date d'inscription jeudi 4 décembre 2008 Statut Membre Dernière intervention 8 novembre 2022
29 juil. 2022 à 16:09

Pour faire suite à mon poste, voila ma problèmatique.

J'ai découvert qu'en fait c'était un problème de requête, car lors de l'export de la base mysql, il n'y avait que les données brut, pas de clé primaire.

J'ai donc pour chacune des tables rajouté une colonne que je nommerais "identifiant" en auto-increment, donc j'ai fait cela sous phpmyadmin et il m'a créé les colonnes sans problemes, voici un peu la structure des mes tables :

Lorsque j'ai créé pour chaque tables ( sous mysql phpmyadmin) la colonne id, en début de table, ça marché et il était en auto increment, du coup les colonnes id se sont rempli.

Pour chacune des tables, voici leur nombre de ligne :

table0: 1390 lignes

table1: 62 347

table2 : 126164

table3 : 15 589 

table 4: 16 000.

moi je ne vais faire que de la consultation, pas d'insertion.

Voici la requete que j'utilise : 

marequete = " select t0.code ,
t0.siret,                                        
t0.numentreprise,                     
t0.solde,              
t0.datesolde,                      
t0.champs,                    
t1.nomentreprise,                    
t2.libelle,                 
t2.base                   
t2.emission,                      
t1.debit,                   
t1.datefin,                    
t1.daterec,                     
t2.colonnex,   
t1.colonnex, 
t3.colonnez,           
t3.colonnez,               
t3.TESENCFIN, " +                            
t1.colonnetotale " +                 
 from table0 t0 " +
 left join table1 t1 on t0.numsiret = t1.numsiret " +
 left join table2 t0 on t0.numsiret = t2.numsiret " +
 left join table3 t3 on t3.numsiret = t1.numsiret " +                                               
 where t0.siret = " + monsiren[a] + "";

mais j'ai l'impression que plus ma requete est longue, plus le programme est long ( j'ai fais le test ) et je n'arrive pas à l'optimiser. J'ai fais ma jointure sur le numero de siret et j'ai utilisé left join, car d'une table à l'autre, un siret peut ne pas être là.

Par contre si je fais ma jointure sur l'id ça ne marche pas , car ce sont des donnée autoincrement, que j'ai créé dans l'export des tables brut qui a été réalisé, vous voyez un peu la complexité de la chose, d'où la jointure sur le numero de siret.

Y a t-il un moyen de l'optimiser pour rendre le programme viable?

sinon pour ma part je suis en congés fin du mois d'aout) ça va faire du bien^

Un grand merci ^

0
yg_be Messages postés 23392 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 16 décembre 2024 1 556
30 juil. 2022 à 09:24

Il est peut-être préférable de commencer une nouvelle discussion, ce serait plus clair.

Je pense que tes tables sont mal structurées, et que ton problème principal, ce n'est pas un problème de performance, mais le fait que les données que tu vas récupérer de ta requête ne sont pas correctes.  Pour structurer correctement ces tables, il faut tenir compte de à quoi elles servent, et tu ne nous donnes aucune information à ce sujet.

Je pense qu'il faut adapter ainsi:

  • le champ numsiret devrait probablement être présent dans une seule table, et ne pas être utilisé pour les jointures
  • pour lier deux tables, tu dois utiliser les id.  Par exemple, si tu as une table facture et une table entreprise, tu auras dans la table facture un champ avec id_entreprise.
  • les jointures se font avec les id

Il est possible que le problème vienne de l'exportation, qui aurait laissé tombé les liens entre le tables.

1