So ändern Sie langsam parametrisierte Einfügungen in schnelle Massenkopien (auch aus dem Speicher)

Ich hatte so etwas in meinem Code (.Net 2.0, MS SQL)

SqlConnection connection = new SqlConnection(@"Data Source=localhost;Initial
Catalog=DataBase;Integrated Security=True");
  connection.Open();

  SqlCommand cmdInsert = connection.CreateCommand();
  SqlTransaction sqlTran = connection.BeginTransaction();
  cmdInsert.Transaction = sqlTran;

  cmdInsert.CommandText =
     @"INSERT INTO MyDestinationTable" +
      "(Year, Month, Day, Hour,  ...) " +
      "VALUES " +
      "(@Year, @Month, @Day, @Hour, ...) ";

  cmdInsert.Parameters.Add("@Year", SqlDbType.SmallInt);
  cmdInsert.Parameters.Add("@Month", SqlDbType.TinyInt);
  cmdInsert.Parameters.Add("@Day", SqlDbType.TinyInt);
  // more fields here
  cmdInsert.Prepare();

  Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

  StreamReader reader = new StreamReader(stream);
  char[] delimeter = new char[] {' '};
  String[] records;
  while (!reader.EndOfStream)
  {
    records = reader.ReadLine().Split(delimeter, StringSplitOptions.None);

    cmdInsert.Parameters["@Year"].Value = Int32.Parse(records[0].Substring(0, 4));
    cmdInsert.Parameters["@Month"].Value = Int32.Parse(records[0].Substring(5, 2));
    cmdInsert.Parameters["@Day"].Value = Int32.Parse(records[0].Substring(8, 2));
    // more here complicated stuff here
    cmdInsert.ExecuteNonQuery()
  }
  sqlTran.Commit();
  connection.Close();

MitcmdInsert.ExecuteNonQuery () Auskommentiert Dieser Code wird in weniger als 2 Sekunden ausgeführt. Bei SQL-Ausführung dauert es 1m 20 sec. Es gibt ungefähr 0,5 Millionen Rekorde. Tisch wird vorher geleert. Eine SSIS-Datenflussaufgabe mit ähnlicher Funktionalität dauert etwa 20 Sekunden.

Masseneinsatzwar keine Option (siehe unten). Ich habe während dieses Imports ein paar ausgefallene Sachen gemacht.Mein Testgerät ist Core 2 Duo mit 2 GB RAM.Bei der Suche im Task-Manager wurde die CPU nicht vollständig vergrößert. IO schien auch nicht voll ausgelastet zu sein.Das Schema ist einfach wie die Hölle: Eine Tabelle mit AutoInt als Primärindex und weniger als 10 Zoll, winzigen Zoll und Zeichen (10).

Nach einigen Antworten hier fand ich, dass es möglich ist, auszuführenMassenkopie aus dem Speicher! Ich weigerte mich, Massenkopien zu verwenden, da ich dachte, dass dies aus einer Datei erfolgen muss ...

Jetzt benutze ich dies und es dauert ungefähr 20 Sekunden (wie SSIS Aufgabe)

  DataTable dataTable = new DataTable();

  dataTable.Columns.Add(new DataColumn("ixMyIndex", System.Type.GetType("System.Int32")));   
  dataTable.Columns.Add(new DataColumn("Year", System.Type.GetType("System.Int32")));   
  dataTable.Columns.Add(new DataColumn("Month", System.Type.GetType("System.Int32")));
  dataTable.Columns.Add(new DataColumn("Day", System.Type.GetType("System.Int32")));
 // ... and more to go

  DataRow dataRow;
  object[] objectRow = new object[dataTable.Columns.Count];

  Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

  StreamReader reader = new StreamReader(stream);
  char[] delimeter = new char[] { ' ' };
  String[] records;
  int recordCount = 0;
  while (!reader.EndOfStream)
  {
    records = reader.ReadLine().Split(delimeter, StringSplitOptions.None);

    dataRow = dataTable.NewRow();
    objectRow[0] = null; 
    objectRow[1] = Int32.Parse(records[0].Substring(0, 4));
    objectRow[2] = Int32.Parse(records[0].Substring(5, 2));
    objectRow[3] = Int32.Parse(records[0].Substring(8, 2));
    // my fancy stuf goes here

    dataRow.ItemArray = objectRow;         
    dataTable.Rows.Add(dataRow);

    recordCount++;
  }

  SqlBulkCopy bulkTask = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null);
  bulkTask.DestinationTableName = "MyDestinationTable"; 
  bulkTask.BatchSize = dataTable.Rows.Count;
  bulkTask.WriteToServer(dataTable);
  bulkTask.Close();

Antworten auf die Frage(12)

Ihre Antwort auf die Frage