2009-01-08 3 views
23

Ich versuche, den Umfang des Speicherbedarfs, der mit einer .NET-DataTable verknüpft ist, und mit einzelnen DataRows innerhalb einer Tabelle zu behandeln.
Mit anderen Worten, wie viel mehr Speicher belegt eine Datentabelle als das, was benötigt würde, um ein korrekt typisiertes Array jeder Datenspalte zu speichern?
Ich denke, es wird einige grundlegende Tabelle Overhead, plus einige Menge pro Spalte und dann wieder einen zusätzlichen Betrag pro Zeile.Welchen Speicherbedarf hat das Speichern von Daten in einer .NET DataTable?

Also kann jemand eine Schätzung (und, ich denke, Erklärung!) Von jedem/jeder dieser drei Arten von Overhead geben?

Antwort

22

Nun, vergessen Sie nicht, dass ein DataTable speichert 2? 3? Versionen der Daten - original und aktualisiert (möglicherweise eine andere?). Es hat auch viele Referenzen, da es zellenbasiert ist , und Boxen für alle Werttypen. Es wäre schwierig, den genauen Speicher zu quantifizieren ...

Persönlich verwende ich sehr selten DataTable - getippte POCO-Klassen sind aus meiner Sicht eine viel vernünftigere Wette. Ich würde kein Array (direkt) verwenden, obwohl - List<T> oder BindingList<T> oder ähnliches viel häufiger wäre.

Als eine grobe Maßnahme könnten Sie eine Menge Tabellen usw. erstellen und die Speicherauslastung betrachten; zum Beispiel zeigt die folgenden a ~ 4.3 Faktor - also mehr als 4 mal so teuer, aber natürlich hängt, dass eine Menge von der Anzahl der Spalten vs Reihen vs Tabellen etc:

// takes **roughly** 112Mb (taskman) 
    List<DataTable> tables = new List<DataTable>(); 
    for (int j = 0; j < 5000; j++) 
    { 
     DataTable table = new DataTable("foo"); 
     for (int i = 0; i < 10; i++) 
     { 
      table.Columns.Add("Col " + i, i % 2 == 0 ? typeof(int) 
           : typeof(string)); 
     } 
     for (int i = 0; i < 100; i++) 
     { 
      table.Rows.Add(i, "a", i, "b", i, "c", i, "d", i, "e"); 
     } 
     tables.Add(table); 
    } 
    Console.WriteLine("done"); 
    Console.ReadLine(); 

vs

// takes **roughly** 26Mb (taskman) 
    List<List<Foo>> lists = new List<List<Foo>>(5000); 
    for (int j = 0; j < 5000; j++) 
    { 
     List<Foo> list = new List<Foo>(100); 
     for (int i = 0; i < 100; i++) 
     { 
      Foo foo = new Foo { Prop1 = "a", Prop3 = "b", 
       Prop5 = "c", Prop7 = "d", Prop9 = "e"}; 
      foo.Prop0 = foo.Prop2 = foo.Prop4 = foo.Prop6 = foo.Prop8 = i; 
      list.Add(foo); 
     } 
     lists.Add(list); 
    } 
    Console.WriteLine("done"); 
    Console.ReadLine(); 

(basierend auf)

class Foo 
{ 
    public int Prop0 { get; set; } 
    public string Prop1 { get; set; } 
    public int Prop2 { get; set; } 
    public string Prop3 { get; set; } 
    public int Prop4 { get; set; } 
    public string Prop5 { get; set; } 
    public int Prop6 { get; set; } 
    public string Prop7 { get; set; } 
    public int Prop8 { get; set; } 
    public string Prop9 { get; set; } 
} 
+0

@Marc - Kein Schaden, um eine Ref Erwähnung AcceptChanges und Freunde können verwendet werden, um den Bestand der Versionen zu manipulieren, die gespeichert werden. @Nick: Bottom Line ist, wenn Sie Licht wollen, ist DataX nicht der Ort, um zu suchen, und Sie müssen nicht einmal messen, um dorthin zu gelangen. Warum nicht einige Tests nach Maß schreiben? –

+0

@Ruben - Arbeiten an es; -p –

+0

Marc DataTable Box Werte nicht, speichert es Werttypen in typisierten Arrays. –

8

Overhead ist ziemlich niedrig, wenn Sie keine Indizes für Spalten definieren. Wenn Sie String-Caching verwenden, können Sie einen ziemlich geringen Speicherbedarf haben: Verwenden Sie ein HashSet oder ein Dictionary, um nur 1 Zeichenfolgeninstanz jedes Zeichenfolgenwerts zu verwenden. Das hört sich merkwürdig an, aber wenn Sie Daten aus einer Datenbank abrufen und mehrere Zeilen mit demselben Zeichenfolgenwert haben (z. B. "ALFKI"), sind die Zeichenfolgenwerte gleich, die Zeichenfolgeninstanzen jedoch nicht: Die Zeichenfolge wird mehrfach gespeichert Erinnerung. Wenn Sie zum Ausfiltern doppelter Instanzen zum ersten Mal ein HashSet verwenden, verwenden Sie praktisch überall in Ihrer Datentabelle die gleiche Zeichenfolgeninstanz für 1 Zeichenfolgenwert. Dies kann den Speicherbedarf erheblich reduzieren. Natürlich, wenn die String-Werte irgendwo statisch definiert sind (also nicht von einer externen Quelle gelesen werden), ist es den Aufwand nicht wert.

+0

Sollte das nicht der "String Interning" -Mechanismus von .NET für Sie erledigen? – anakic

+0

@AntonioNakicAlfirevic .NET nicht intern _every_ string - nur String-Literale in Code oder Strings, die ausdrücklich mit 'String.Intern' interniert sind. –

4

Es hängt davon ab, wie viele Daten und welche Art von Daten Sie speichern. Je mehr Daten, desto mehr Speicher. Mit der Datentabelle ist ein gewisser Mehraufwand verbunden, der sie etwas teurer macht. Sie müssen auch auf den großen Objekt-Heap achten. Wenn Sie Objekte über 85 KB speichern, wird das Objekt in der LOH gespeichert. Dies kann Ihrer Garbage-Collection Schaden zufügen, da eine vollständige Sammlung erforderlich ist. Wenn Sie zum Testen bereit sind, schauen Sie in einen Speicherprofiler, um den Speicherbedarf der Datentabelle zu beobachten.

+0

Guter Tipp mit den Saiten; +1 für das allein ;-p –