views:

2927

answers:

6

I am attempting to insert a mass of records into SQL Server 2005 from Vb.Net. Although the insertion is working fine, I am doing my best to try to make it as fast as possible. Currently, it takes ~ 11 mins for 100,000 records. What would be the suggested approach to inserting a large number of records into SQL Server from an Application?

My current apporach is basically opening the connection, iterating through my list of information and firing off individual sql insert statments, and then closing the connection. Anyone have a better suggestion on how to do this?

Current Function:

Public Sub BatchInsert(ByVal ParamCollections As List(Of SqlParameter()))

 Dim Conn As SqlConnection = New SqlConnection(DBHelper.DatabaseConnection)
 Using scope As TransactionScope = New TransactionScope()
 Using Conn

  Dim cmd As SqlCommand = New SqlCommand("sproc_name", Conn)

  Conn.Open()
  cmd.CommandType = CommandType.StoredProcedure

  For i = 0 To ParamCollections.Count - 1

   cmd.Parameters.Clear()
   cmd.Parameters.AddRange(ParamCollections(i))
   cmd.ExecuteNonQuery()

  Next

  Conn.Close()
  scope.Complete()
 End Using
 End Using

End Sub
+14  A: 

Use the SqlBulkCopy class, it will be able to run through those 100K rows much faster than individual inserts.

Oh, and if you can, I would urge you to implement a IDataReader capable class, to feed the SqlBulkCopy.WriteToServer(IDataReader) method, this will allow you to produce data sequentially, one row at a time. If you are importing from a text file, as an example, building some IEnumerable<T> methods that uses yield return and converting it to a IDataReader object will allow you to feed data to the server very naturally.

To counter the loss of rollback ability with BCP, you can transfer the data into a temporary table, and then execute normal INSERT INTO statements on the server afterwards, bulk-transferring the data from the temporary table into the production table, this will allow you to use a transaction for the last transfer part, and will still run a lot faster than your original individual insert statements.

EDIT: and Here's an example (C#, but should be easy to convert to VB.Net) of the usage of the bulk load API.

Lasse V. Karlsen
So long as the OP is OK with not logging these transactions, this is great. Using BCP will remove the ability to rollback the data (not like its really used most of the time anyway).
StingyJack
I am looking into the Bulk Copy now. It looks as if I will need to convert my data into a DataTable in order to leverage the Bulk Copy. Will the process of creating and loading the DataTable offset the Build copy gains?
Nathan
No. The time required to build the datatable will be tiny compared to the time you're spending now.
Michael Haren
For code to convert an IEnumerable<T> to an IDataReader, see this question: http://stackoverflow.com/questions/2258310/get-an-idatareader-from-a-typed-list Very useful!
Daniel Plaisted
A: 

It depends how the bulk copy class is implemented. But there is a command line tool included with installs of SQL Server that does exactly this (it's probably the same). It's called "bcp". I'm using it right now and it should be able to storm through 100k rows in a matter of seconds.

MSDN documentation refers to it as the "bulk import" utility.

Mark Canlas
+1  A: 

There's also a stored proc (called Bulk Insert) that will do the trick for you.. It uses bcp under the covers.

check out this link to see syntax

link text

Charles Bretana
+2  A: 

Put your data to be imported into a csv file and run the bcp utility on the data. You can't get any faster with sequential calls inserting single rows at a time, you certainly need a bulk utility if you want performance.

The SQLBulkCopy class will allow you to transmit all the data in a collection so the server can process everything at once, eliminating the back and forth. So if you want to avoid creating temporary files (which I would), then look to that class.

Just having the connection remain open is a good start, but you still have the overhead of sending a row, having SQL store it, return a result, and then you must iterate to the next row.

Adam
+2  A: 

here are some speed comparisons of different methods of import text files into sql server: http://weblogs.sqlteam.com/mladenp/archive/2006/07/22/10742.aspx

hope it helps.

Mladen Prajdic
+5  A: 

Thanks to everyone's help, I was able to complete my task. The SQLBulkCopy fit my needs perfectly (although there were some other excellent suggestions). Using SqlBulkcopy,the time went from 11 mins to 45 seconds. I can't believe the difference!

For future reference, here are a few bits of information:

  • To use SQL Bulk Copy, your data has to be in the form of a DataSet, DataReader, or DataTable. Some XML is allowed as well.

Basic Implementation code:

    Public Sub PerformBulkCopy(ByVal dt As DataTable)

 Using Conn As SqlConnection = New SqlConnection(DBHelper.DatabaseConnection)
  Conn.Open()

  Using s As SqlBulkCopy = New SqlBulkCopy(Conn)

   s.DestinationTableName = "TableName"
   s.WriteToServer(dt)
   s.Close()

  End Using

  Conn.Close()
 End Using
End Sub

Very informative link that I found:

Using Sql Bulk Copy

Thanks to all for the help! I sincerely appreciate it.

Nathan