Laden...

Problem beim deserialisieren von großen Datatables --> System.StackOverflowException

Erstellt von basti81 vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.010 Views
B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren
Problem beim deserialisieren von großen Datatables --> System.StackOverflowException

Hallo, ich lese zwar schon länger in diesem Forum mit, aber das hier mein erster Thread.
Ich hoffe ich habe alle Regeln befolgt 😃.

Zur meinem Problem:

Ich bekomme folgende Exception, wenn ich eine große DataTable (ca. 2000 x 20000 Zellen) versuchte von deserialisieren (egal ob mit BinaryFormatter oder XmlSerializer):

'Eine nicht behandelte Ausnahme des Typs "System.StackOverflowException" ist in System.Xml.dll aufgetreten.'

Ich serialisiere das DataTable mit (im Falle des XmlSerializer):


public static void XMLSerialisieren<T>(T objekt, string path)
        {
            XmlSerializer mySerializer = new XmlSerializer(typeof(T));
            StreamWriter myWriter = new StreamWriter(path);
            mySerializer.Serialize(myWriter, objekt);
            myWriter.Close();
            myWriter.Dispose();
        }

und deserialisiere es mit :


public static void XMLDeserialisieren<T>(out T objekt, string path)
        {
            XmlSerializer ser = new XmlSerializer(typeof(T));
            StreamReader sr = new StreamReader(path);
            objekt = (T)ser.Deserialize(sr);
            sr.Close();
            sr.Dispose();
        }

Am Speicher sollte es nicht liegen, ich hab 16GB (win7 x64).

Vielleicht kennt jemand eine Lösung.
Bei einschlägigen Suchmaschinen könnte ich keine Lösung finden!
Danke schonmal im Voraus.

verwendetes Datenbanksystem: <DataTable>

G
538 Beiträge seit 2008
vor 12 Jahren

Ich bin mir nicht sicher, wie das serialisieren der Datatable intern abläuft, aber scheinbar ist deine schlicht und ergreifen zu groß (und ich würde auf zu "breit" tippen). StackOverflow tritt ja meistens bei ner zu großen Rekursionstiefe auf ...

Du könntest nun entweder versuchen jeweils nur einen Teil zu serialisieren (also zum Beispiel 4 Tabellen á 500 Spalten) oder du könntest versuchen diese kleineren zu serialisieren.

Ein weiterer Versuch wäre es die Tabelle erst in XML zu schreiben und dann selbiges zu Serialisieren.

Und als letztes fällt mir noch ein:
Schreib deinen eigenen Serialisierer - ist glaube ich gar nicht so schwer.

Der Vorteil der Klugheit liegt darin, dass man sich dumm stellen kann - umgekehrt ist das schon schwieriger (K. Tucholsky)
Das Problem mit Internet-Zitaten ist, dass sie oftmals zu unrecht als authentisch angenommen werden. (K. Adenauer)

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

Danke für deine Antwort.

Das mit kleineren Tabellen wäre auch meine Notlösung gewesen, aber es wäre schon schön, wenn ich alles in einer Tabelle hätte.

Wie meinst du das mit, "erst in XML zu schreiben und dann selbiges zu Serialisieren"?

G
538 Beiträge seit 2008
vor 12 Jahren

Du kannst eine DataTable meines wissens nach in eine XML-Struktur schreiben. Vielleicht funktioniert das (natürlich nur dann, wenn die Funktion nicht selbst den XML-Serializer benutzen sollte).
Mir fällt allerdings der Funktionsnamen grade nicht ein ...

Der Vorteil der Klugheit liegt darin, dass man sich dumm stellen kann - umgekehrt ist das schon schwieriger (K. Tucholsky)
Das Problem mit Internet-Zitaten ist, dass sie oftmals zu unrecht als authentisch angenommen werden. (K. Adenauer)

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

[DataTable] .WriteXmlSchema();

Okay danke, ich versuche mal meine Daten in kleinere Tabellen zu schreiben.

F
10.010 Beiträge seit 2004
vor 12 Jahren

2.000x20.000 Zellen?
Das sind 40.000.000 Zellen und da hast du gleich locker beim deserialisieren den gesamten speicher voll.

Warum meinst du so grosse DataTables benutzen zu müssen?

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

Naja anlegen könnte ich das DataTable ja problemlos und die serialisierte Tabelle ist 1 GB groß.
Müßte also auch in den Speicher passen.

Sind auch glaube keine 20.000 Spalten, eher weniger, war nur eine Schätzung und viele Werte sind ja DBNull.

F
10.010 Beiträge seit 2004
vor 12 Jahren

Nocheimal, warum meinst du solche Monster benutzen zu müssen?
Was soll das wirklich geben?
Und eine DataTable musst du nicht serialisieren, da reicht ein Write/ReadXml

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

Wie frage ist doch nicht warum ich die Daten haben möchte, sondern warum .Net gesicherte Werte nicht wieder herzustellen kann (im Speicher passen sie ja!).

Aber da du gefragst, will ich dir auch antworten:

Die Tabelle ist eine Document-Term-Matrix, d.h. eine Zeile stellt ein Dokument dar und die Spalten sind die gestemmten Wörter und die DataTable ist hier sehr bequem mit ihrer SELECT - Funktion.
Ich weiß für richtig viele Daten gibt es bessere Repräsentationsarten hierfür als eine Matrix, z.B. in Form einer Inverted Index Liste.

Aber für dieses Problem ist die Datenmenge sehr überschaubar.
Und das Deserialisierungsproblem ist mir schon häufiger begegnet (nicht nur bei DataTables), und hab nie eine Antwort gefunden.

Mit Write/ReadXml hast du teilweise recht, Hatte ich auch vorher benutzt. Ich habe aber den XmlSerializer verwendet, da für ReadXml die Tabellenstruktur der Zieltabelle schon bekannt seien muss (was nicht der Fall ist).

Bill Gates said we should never need more than 64K of RAM

1.820 Beiträge seit 2005
vor 12 Jahren

Hallo!

Mit Read/WriteXmlSchema kannst du auch die beschreibung der Tabelle festlegen bzw. einlesen.

EDIT: Dass dabei nur die Struktur geschrieben wird, ist beabsichtigt, damit unabhängig davon mehrere Datendateien erstellt werden können.

Nobody is perfect. I'm sad, i'm not nobody 🙁

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

Danke, aber WriteXmlSchema schreibt nur die Struktur ohne Daten!

Ich versuch mal:
.WriteXmlSchema(..)
.WriteXml(..)
...
.ReadXmlSchema(...)
.ReadXml(...)

ist zwar komplizierter und ich habe dann zwei Datei, aber ich probier es mal.

Leider funktioniert es auch so nicht!
Auch hier kommt beim Einlesen die Exception:

'Eine nicht behandelte Ausnahme des Typs "System.StackOverflowException" ist in System.Xml.dll aufgetreten.'

Sonst noch Ideen zur Frage der Exception (System.StackOverflowException)?

Gelöschter Account
vor 12 Jahren

Der Stack ist nun mal begrenzt. Das hat auch nicht unbedingt was mit .NET zu tun. Und es ist auch niemand auf die Idee gekommen 40 Millionen Datenzellen zu Serialisieren oder zu Deserialisieren... In einem Stück.
Dabei ist es nicht mal die Menge der Rows, sondern eher die Exorbitante Anzahl an Columns, denn niemand auf der Welt kommt auf die Idee eine Tabelle mit 2000! Colums anzulegen... oder gar über die Idee einer Idee sowas zu machen nachzudenken. Das ist dann auch der Grund, warum du zu diesem Thema nichts findest.

Da du ohnehin schon mit Select & Co arbeitest... warum denn keine embedded Datenbank? Dann kannst du evtl. auch ein schönes, schlankes und vor allem Relationales Modell dahinter hängen und so das System übersichtlicher machen?

F
10.010 Beiträge seit 2004
vor 12 Jahren
  1. Nicht alles was einfach zu benutzen ist, ist auch für jedes Problem benutzbar.
  2. Natürlich kannst du bei WriteXml auch noch einen weiteren Parameter angeben, der das Schema mit schreibt.
  3. Beim einlesen der XML passieren ja viel mehr als "nur" die XML einzulesen und dann so wie sie ist in eine DT zu packen.

Und durch LinQ to Object zieht auch das Select nicht wirklich als Ausrede.

B
basti81 Themenstarter:in
8 Beiträge seit 2011
vor 12 Jahren

Bleibt die Erkenntnis, das alles seine Limitierung hat und nicht alles, was man Speichern/Serialisieren auch nachher noch laden kann.
Da werde ich dann ganz old-school meine eigenen Datenaustauschmethoden schreiben und die Werte in einer csv-Datei sichern, sind ja in diesem Fall nur strings und floats.

@JAck30lena: Es scheint aber nicht die Spaltenanzahl, sondern die Größe das Problem zu sein. Dieses Problem trat auch schon mal bei einer 100 x 6 Tabelle auf, da waren aber der Zellinhalt größer (längere strings).

D
290 Beiträge seit 2006
vor 12 Jahren
  1. Nicht alles was einfach zu benutzen ist, ist auch für jedes Problem benutzbar.
  2. Natürlich kannst du bei WriteXml auch noch einen weiteren Parameter angeben, der das Schema mit schreibt.
  3. Beim einlesen der XML passieren ja viel mehr als "nur" die XML einzulesen und dann so wie sie ist in eine DT zu packen.

Und durch LinQ to Object zieht auch das Select nicht wirklich als Ausrede.

Ich glaube nicht, dass wen jemand eine Frage postet, er solche Antworten erwartet. Ich konnte es selber nicht glauben und hab seine Funktionen getestet mit dem gleichen Resultat. Als "Monster" würde ich das jetzt auch nicht bezeichnen. 1 GB Arbeitsspeicher für eine Tabelle ist doch kein Thema. Aus meiner Sicht ist das ein unbekannter Kompiler-Fehler in C# oder eine andere Lösung.
Sinn der Serialisierung sollte es doch sein jede Klasse (auch DT) im Speicher in eine Datei speichern zu können. Scheinbar macht er das auch, jedoch zurück kann er das dann nicht mehr.

Schließe mich also der Suche an...

F
10.010 Beiträge seit 2004
vor 12 Jahren
  1. Wenn du auf eine Frage immer erwartest das man dir bei der Herangehensweise recht gibt, ist die Frage als solche schon mal Sinnlos.

  2. Wenn du den Prozess beim Deserialisieren nicht durchschaust, ist sicherlich 1GB "nicht viel", da du aber dabei haufenweise Zwischenobjekte erzeugst ist der vorhandene Speicher unter .NET recht schnell weg, zumal wie der OP feststellen musste einiges davon auf dem Stack passiert.

  3. Es gibt Objekte, und die DT gehört dazu, die eine eigene Serialisierung bereitstellen, die speziell auf sie abgestimmt ist, und dann eine andere zu benutzen ist sehr kontraproduktiv.
    Bei einer DT würde z.b. mit std Serialisierung versucht werden neben den Properties selber auch noch die Textrepresentation zu speichern.

Auch wenn Du es evtl nicht einsiehst, auch Kritik an der Herangehensweise kann Zielführend sein.

Gelöschter Account
vor 12 Jahren

Aus meiner Sicht ist das ein unbekannter Kompiler-Fehler in C#

Was hat das mit dem Kompiler zu tun?