Werfen Sie einen Blick auf das folgende Programm. Es ist ziemlich selbsterklärend, aber ich werde es trotzdem erklären :)Extremer Leistungsunterschied bei der Verwendung von DataTable.Add
Ich habe zwei Methoden, eine schnell und eine langsam. Diese Methoden machen genau das Gleiche: Sie erstellen eine Tabelle mit 50.000 Zeilen und 1000 Spalten. Ich schreibe in eine variable Anzahl von Spalten in der Tabelle. Im folgenden Code habe ich 10 (NUM_COLS_TO_WRITE_TO
) ausgewählt.
Mit anderen Worten, nur 10 Spalten von 1000 werden tatsächlich Daten enthalten. OK. Der nur Unterschied zwischen den beiden Methoden ist, dass das schnelle füllt die Spalten und dann Anrufe DataTable.AddRow
, während die langsame macht es nach. Das ist es.
Der Leistungsunterschied ist jedoch schockierend (für mich jedenfalls). Die schnelle Version ist fast vollständig unabhängig von der Anzahl der Spalten, in die wir schreiben, während die langsame linear ansteigt. Wenn zum Beispiel die Anzahl der Spalten, in die ich schreibe, 20 beträgt, dauert die schnelle Version 2,8 Sekunden, aber die langsame Version übernimmt eine Minute.
Was in der Welt könnte hier möglicherweise vor sich gehen?
dachte ich, dass vielleicht dt.BeginLoadData
Zugabe einen Unterschied machen würde und es zu einem gewissen Grad hat, ist es die Zeit gebracht von 61 Sekunden bis ca. 50 Sekunden, aber das ist immer noch ein großer Unterschied.
Natürlich ist die offensichtliche Antwort: "Nun, mach es nicht so." OK. Sicher. Aber was in der Welt verursacht das? Ist das erwartetes Verhalten? Ich habe es nicht erwartet. :)
public class Program
{
private const int NUM_ROWS = 50000;
private const int NUM_COLS_TO_WRITE_TO = 10;
private const int NUM_COLS_TO_CREATE = 1000;
private static void AddRowFast() {
DataTable dt = new DataTable();
//add a table with 1000 columns
for (int i = 0; i < NUM_COLS_TO_CREATE; i++) {
dt.Columns.Add("x" + i, typeof(string));
}
for (int i = 0; i < NUM_ROWS; i++) {
var theRow = dt.NewRow();
for (int j = 0; j < NUM_COLS_TO_WRITE_TO; j++) {
theRow[j] = "whatever";
}
//add the row *after* populating it
dt.Rows.Add(theRow);
}
}
private static void AddRowSlow() {
DataTable dt = new DataTable();
//add a table with 1000 columns
for (int i = 0; i < NUM_COLS_TO_CREATE; i++) {
dt.Columns.Add("x" + i, typeof(string));
}
for (int i = 0; i < NUM_ROWS; i++) {
var theRow = dt.NewRow();
//add the row *before* populating it
dt.Rows.Add(theRow);
for (int j=0; j< NUM_COLS_TO_WRITE_TO; j++){
theRow[j] = "whatever";
}
}
}
static void Main(string[] args)
{
var sw = Stopwatch.StartNew();
AddRowFast();
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);
sw.Restart();
AddRowSlow();
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);
//When NUM_COLS is 5
//FAST: 2754.6782
//SLOW: 15794.1378
//When NUM_COLS is 10
//FAST: 2777.431 ms
//SLOW 32004.7203 ms
//When NUM_COLS is 20
//FAST: 2831.1733 ms
//SLOW: 61246.2243 ms
}
}
aktualisiert
Aufruf theRow.BeginEdit
und theRow.EndEdit
in der langsamen Version macht die langsame Version mehr oder weniger konstant (~ 4 Sekunden auf meinem Rechner). Wenn ich tatsächlich hatte einige Einschränkungen auf dem Tisch, ich denke, das könnte für mich sinnvoll sein.
Ich denke, Erklärung ist ziemlich einfach. Wenn 'DataRow' außerhalb der Tabelle liegt, löst das Ändern von Daten keine Prüfungen/Verifizierungen/Benachrichtigungen usw. aus. Um eine genauere Erklärung zu erhalten, würde ich' DataRow's Spaltenwerteinstellungs-Code betrachten ... – Dennis
@Dennis, aber ich dachte Der Zweck von BeginLoadData war es, "Benachrichtigungen, Indexwartung und Einschränkungen beim Laden von Daten auszuschalten". Außerdem scheint es, als wäre etwas 30 * mal * langsamer ein ziemlich großer Unterschied. – aquinas
Außerdem scheint mir seltsam, dass die Anzahl der Spalten in der Tabelle die Laufzeit beeinflusst. Das heißt, wenn ich 10 Spalten aktualisiere und da nur * 10 Spalten sind, dann läuft es völlig in Ordnung. Also, was macht .NET mit all diesen Spalten, die ich nie anfasse? Schießen Ereignisse auch auf diese? Scheint seltsam. – aquinas