How to change slow parameterized inserts to fast copy (even from memory)

I had such code in my 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();

With cmdInsert.ExecuteNonQuery () commented out that this code is executed in less than 2 seconds. When executing SQL, it takes 1 m 20 sec. There are about 0.5 million entries. The table is empty earlier. An SSIS data flow task with similar functionality takes about 20 seconds.

  • Bulk insertion was not an option (see below). During this import, I did some fancy stuff.
  • My test machine is a Core 2 Duo with 2 GB of RAM.
  • When viewed in the task manager, the task manager was not completely closed. IO was also not fully used.
  • , : AutoInt 10 ints, ints (10).

, ! , , ...

, 20 (, SSIS)

  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();
+3
12

, , SqlBulkCopy .

DataTable DataTable, SqlBulkCopy. WriteToServer, .

+9

? , .

, , corect, BulkInsert.

+3

1 0,5 . 0,00012 .

- ? , , .

+2

8333 ... ?

+1

, , .

, 500 000 - (.. ) .

, , /, , .

- . , , .

SSIS , - , .

+1

, 58 500 000 , 10 000 . ( , localhost, ), , , .

- , ? , , . SQL- , SQL Server, . , , .

0

, . Bulk-Insert.

( . BulkInsert

0

, , , tbTrafficLogTTL. , , , :

  • - GUID, - CLUSTERED.
  • - UNIQUE .
  • .

, , , .

, Year, Month, Day, Hour, Minute, Second datetime2 timestamp, . , . , , , - , - . .

0

. 500 000 SQL . BulkInsert SQL. "", 2 , 31 , .

0

bcp. , , BULK INSERT, - . 500 000 500 000 , - , , .

If you put in an order different from your clustered index, you also need to deal with the time requirement for reorganizing the physical data on disk. There are many variables here that could make your request run slower than you would like.

~ 10,000 transactions per second are not scary for individual inserts going roundtripping from code /

0
source

BULK INSERT = bcp with permission

You can load INSERT to reduce the SQLDataAdaptor.UpdateBatchSize = 10000 cycle gives 50 rounds.

You still have 500k inserts though ...

Article

MSDN

0
source

Source: https://habr.com/ru/post/1697458/


All Articles