Announcement

Collapse
No announcement yet.

Benötige Hilfe bei Datenbank lesen/schreiben (Performance)

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Benötige Hilfe bei Datenbank lesen/schreiben (Performance)

    Hallo zusammen,

    ich bin nicht gerade geschickt wenn es um den Datenbankzugriff geht und das rächt sich gerade.

    Ich muss Daten aus einer Tabelle einlesen, in jeder Zeile eine bestimmte Spalte (den Wert darin) bearbeiten und dann den ganzen Kram zurück auf die Datenbank schreiben.
    Nun hat meine Testdatenbank in jener Tabelle ca. 680.000 Datensätze. Das Lesen dauert ewig und irgendwann bekomme ich eine OutOfMemory-Exception.

    Hier mein Code:
    [highlight=c#]
    conString = "Password=" + txtPasswort.Text + ";Persist Security Info=True;User ID=" + txtLogin.Text + ";Initial Catalog=" + txtDatenbank.Text + ";Data Source=" + cmbServer.SelectedText;
    cnn = new SqlConnection(conString);
    cnn.Open();
    SqlCommand myCommand = new SqlCommand("SELECT TextID, Objektart, ObjektID, Sprache, MemoText FROM TM_Texte", cnn);
    DataTable dt = new DataTable();
    SqlDataAdapter da = new SqlDataAdapter(myCommand);
    SqlCommandBuilder cbuilder = new SqlCommandBuilder(da);
    da.Fill(dt);
    pbFortschritt.Value = 0;
    pbFortschritt.Maximum = (dt.Rows.Count * 10) + 10;

    foreach (DataRow row in dt.Rows)
    {
    string rtf = row["MemoText"].ToString();
    if (rtf != null && rtf != "" && rtf.StartsWith(@"{\rtf"))
    {
    tx.Clear();
    tx.Append(rtf, TXTextControl.StringStreamType.RichTextFormat, TXTextControl.AppendSettings.None);
    tx.Save(out rtf, TXTextControl.StringStreamType.RichTextFormat);

    row["MemoText"] = rtf;
    }
    pbFortschritt.PerformStep();
    }

    da.Update(dt);
    pbFortschritt.PerformStep();
    MessageBox.Show("Konvertierung erfolgreich abgeschlossen", "Fertig", MessageBoxButtons.OK, MessageBoxIcon.Information);
    [/highlight]

    Kann mir jemand sagen, was ich ändern sollte, bzw. besser machen könnte, damit ich dieses Problem vermeiden kann?

    Danke schonmal
    Andi
    Zuletzt editiert von Andreas Mahr; 15.02.2011, 13:03.

  • #2
    Datensätze einzeln einlesen, ändern, zurückschreiben
    Christian

    Comment


    • #3
      ok, hab das mal so umgebaut:

      [highlight=c#]
      conString = "Password=" + txtPasswort.Text + ";Persist Security Info=True;User ID=" + txtLogin.Text + ";Initial Catalog=" + txtDatenbank.Text + ";Data Source=" + cmbServer.SelectedText;
      cnnSelect = new SqlConnection(conString);
      cnnUpdate = new SqlConnection(conString);
      cnnSelect.Open();
      cnnUpdate.Open();
      SqlCommand mySelectCommand = new SqlCommand("SELECT TextID, Objektart, ObjektID, Sprache, MemoText FROM TM_Texte", cnnSelect);
      SqlCommand myUpdateCommand = new SqlCommand("UPDATE TM_Texte SET MemoText = @MemoText WHERE TextID=@TextID AND Objektart=@ObjektArt AND ObjektID=@ObjektID AND Sprache=@Sprache", cnnUpdate);
      myUpdateCommand.Parameters.Add("TextID", SqlDbType.Int);
      myUpdateCommand.Parameters.Add("Objektart", SqlDbType.VarChar);
      myUpdateCommand.Parameters.Add("ObjektID", SqlDbType.Int);
      myUpdateCommand.Parameters.Add("Sprache", SqlDbType.Int);
      myUpdateCommand.Parameters.Add("MemoText", SqlDbType.Text);

      int anzahlDatensätze = (int)new SqlCommand("SELECT Count(*) FROM TM_Texte", cnnSelect).ExecuteScalar();
      pbFortschritt.Value = 0;
      pbFortschritt.Maximum = anzahlDatensätze * 10;
      SqlDataReader reader = mySelectCommand.ExecuteReader();
      while (reader.Read())
      {
      string rtf = reader["MemoText"].ToString();
      if (rtf != null && rtf != "" && rtf.StartsWith(@"{\rtf"))
      {
      tx.Clear();
      tx.Append(rtf, TXTextControl.StringStreamType.RichTextFormat, TXTextControl.AppendSettings.None);
      tx.Save(out rtf, TXTextControl.StringStreamType.RichTextFormat);

      myUpdateCommand.Parameters["MemoText"].Value = rtf;
      myUpdateCommand.Parameters["Objektart"].Value = reader["Objektart"];
      myUpdateCommand.Parameters["ObjektID"].Value = reader["ObjektID"];
      myUpdateCommand.Parameters["TextID"].Value = reader["TextID"];
      myUpdateCommand.Parameters["Sprache"].Value = reader["Sprache"];

      myUpdateCommand.ExecuteNonQuery();
      }
      pbFortschritt.PerformStep();
      }
      MessageBox.Show("Konvertierung erfolgreich abgeschlossen", "Fertig", MessageBoxButtons.OK, MessageBoxIcon.Information);
      [/highlight]

      Jetzt bekomm ich bei der großen Tabelle nach kurzer Zeit einen TimeOut

      Comment


      • #4
        Wenn ich das richtig sehe, werden mit

        SELECT TextID, Objektart, ObjektID, Sprache, MemoText FROM TM_Texte

        ebenfalls alle Sätze gelesen. nur nicht mehr in eine DataTable
        Christian

        Comment


        • #5
          hmm...nein, nicht wirklich. Duch den DataReader hab ich immer genau einen Datensatz am wickel. Oder seh ich das falsch?

          Comment


          • #6
            ok, ich muss zugeben, du hast recht Christian. Aber wie bekomme ich es hin, das ich immer genau einen Datensatz bekomme, und danach dann den nächsten usw bis hin zum letzten?

            Comment


            • #7
              Entweder gibt ein ein Kriterium welches die Row kennzeichnet UND automatisch generiert wird -> bsp eine laufende Nummer. Dann selectest du jeden Datensatz nach dieser Nummer, änderst ihn und schreibst ihn zurück.

              Gibt es kein Kriterium, welches programmatisch nachgebildet werden kann, jedoch jede Row enthält ein solches Kriterium, dann selectest du erst alle diese IDs, fügst diese in eine Liste ein und selectest dann jeden Datensatz anhand dieser ID aus der Liste, änderst ihn und schreibst ihn zurück
              Christian

              Comment


              • #8
                ok, ist noch nicht richtig schöner sauberer Code, aber es funktioniert:

                [highlight=c#]
                conString = "Password=" + txtPasswort.Text + ";Persist Security Info=True;User ID=" + txtLogin.Text + ";Initial Catalog=" + txtDatenbank.Text + ";Data Source=" + cmbServer.SelectedText;
                cnnSelect = new SqlConnection(conString);
                cnnSelect.Open();

                int anzahlDatensaetze = (int)new SqlCommand("SELECT Count(TextID) FROM TM_Texte", cnnSelect).ExecuteScalar();
                int[] id = new int[anzahlDatensaetze];
                int zaehler = 0;
                pbFortschritt.Value = 0;
                pbFortschritt.Maximum = (anzahlDatensaetze * 10) + 10;

                reader = new SqlCommand("SELECT TextID FROM TM_Texte", cnnSelect).ExecuteReader();
                while (reader.Read())
                {
                id[zaehler] = (int)reader["TextID"];
                zaehler++;
                }
                reader.Close();

                pbFortschritt.PerformStep();
                foreach (int i in id)
                {
                DataTable dt = new DataTable();
                SqlDataAdapter da = new SqlDataAdapter(new SqlCommand("SELECT TextID, Objektart, ObjektID, Sprache, MemoText FROM TM_Texte WHERE TextID=" + i, cnnSelect));
                SqlCommandBuilder cbuilder = new SqlCommandBuilder(da);
                da.Fill(dt);
                string rtf = dt.Rows[0]["MemoText"].ToString();
                if (rtf != null && rtf != "" && rtf.StartsWith(@"{\rtf"))
                {
                tx.Load(rtf, TXTextControl.StringStreamType.RichTextFormat);
                tx.SelectAll();
                tx.Selection.FontSize = 11 * 20;

                tx.Save(out rtf, TXTextControl.StringStreamType.RichTextFormat);
                da.Update(dt);
                }
                pbFortschritt.PerformStep();
                }

                MessageBox.Show("Konvertierung erfolgreich abgeschlossen", "Fertig", MessageBoxButtons.OK, MessageBoxIcon.Information);
                [/highlight]

                Comment


                • #9
                  achtung falls dein TextID ein AutoIncrement Wert in der Datenbank ist gibt es spätestens in dem Moment ein Problem wo ein Datensatz gelöscht wird. Da du dann lücken in deiner TextID in der Datenbank hast die du Programmatisch nicht nachvollziehen kannst.

                  Besser du liest wirklich alle ID's aus und liest anhand dessen die Datensätze dann einzeln aus.


                  Mir fällt gerade noch ein da du SQL benutzt kannst du mit Count(Text_ID) die Anzahl der Zeilen auslesen und mit dem Befehl:
                  Code:
                  Select * FROM bla LIMIT untereGrenze, obereGrenze
                  kannst du dir dann sogar mehrere Datensätze holen, diese ändern, speichern und mit dem nächsten Satz anfangen.

                  Gruß
                  Unsere Jugend ist unerträglich, unverantwortlich und entsetzlich anzusehen! - Aristoteles

                  Comment


                  • #10
                    Ich sehe kein Problem in seinem Ablauf durch fehlende IDs.

                    Er zählt die IDs mit dem Wert legt er sich ein Array für die IDs selbst an und liest dann alle IDs aus in dieses Array. Welches dann später benutzt wird jeden Text einzeln zu laden und zu verarbeiten.

                    Ich hätte es evtl. mit einer List<int> gemacht, aber funktionieren sollte seines auch ohne Probleme.

                    Gruß Womble

                    Comment


                    • #11
                      So ist es. Es sei denn jemand löscht während des Programmablaufs einen Datensatz, dann weiß ich nicht was passiert. Aber das sollte nicht vorkommen.
                      Für List<int> war ich zu faul, mich da rein zu lesen

                      Comment


                      • #12
                        ach stimmt habe ich wohl zu schnell überflogen! Vielen Dank für den Hinweis! Allerdings ist die Limit Methode die Ressourcenschonendste da er dort nicht ein u.U. riesige Integer Liste holen muss.
                        Unsere Jugend ist unerträglich, unverantwortlich und entsetzlich anzusehen! - Aristoteles

                        Comment


                        • #13
                          Das Problem mit dem Löschen sollte auch nicht auftreten, da es sich um einen einmaligen Konvertierunglauf handelt...
                          Christian

                          Comment


                          • #14
                            Möglich allerdings sollte man gewappnet sein. Außerdem wäre das mit Limit doch was was man sich merken kann. Macht das leben leichter. Oftmals!
                            Unsere Jugend ist unerträglich, unverantwortlich und entsetzlich anzusehen! - Aristoteles

                            Comment


                            • #15
                              Das mit LIMIT hab ich nicht verstanden, aber ich werd mich da mal durchgoogeln

                              Comment

                              Working...
                              X