2013-06-10 7 views
10

SQL Serverの一時テーブルでC#を使用して挿入パフォーマンスを向上させる方法を探しています。私はSQLBulkCopyを使うべきだと言っている人もいますが、単純にSQL挿入文字列を作成するよりもはるかに遅いと思われるので、何か間違っていなければなりません。 SQLBulkCopyを使用してテーブルを作成するためのC#を使用してSQL Serverの一時テーブルに30,000行を挿入する最速の方法

私のコード以下の通りです:

public void MakeTable(string tableName, List<string> ids, SqlConnection connection) 
    { 

     SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection); 
     cmd.ExecuteNonQuery(); 

     DataTable localTempTable = new DataTable(tableName); 

     DataColumn id = new DataColumn(); 
     id.DataType = System.Type.GetType("System.Int32"); 
     id.ColumnName = "ID"; 
     localTempTable.Columns.Add(id); 

     foreach (var item in ids) 
     { 
      DataRow row = localTempTable.NewRow(); 
      row[0] = item; 
      localTempTable.Rows.Add(row); 
      localTempTable.AcceptChanges(); 
     } 


     using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
     { 
      bulkCopy.DestinationTableName = "##" + tableName; 
      bulkCopy.WriteToServer(localTempTable); 

     } 
    } 

私の挿入は実行に時間がかかるこの方法です。私は私の挿入は別の方法でより速く動作するようになった:

私は文字列として挿入ビットを作成し、一時テーブルステートメントを作成し、私のSQLでそれを参加:挿入文字列の

作成:

public string prepareInserts(string tableName, List<string> ids) 
    { 
     List<string> inserts = new List<string>(); 

     var total = ids.Select(p => p).Count(); 
     var size = 1000; 

     var insert = 1; 

     var skip = size * (insert - 1); 

     var canPage = skip < total; 

     while (canPage) 
     { 
      inserts.Add(" insert into ##" + tableName + @" (ID) values " + String.Join(",", ids.Select(p => string.Format("({0})", p)) 
         .Skip(skip) 
         .Take(size) 
         .ToArray())); 
      insert++; 
      skip = size * (insert - 1); 
      canPage = skip < total; 
     } 

     string joinedInserts = String.Join("\r\n", inserts.ToArray()); 

     return joinedInserts; 

    } 

クエリを作成した後、SQL文の中でそれらを使用する:

inserts = prepareInserts(tableName, ids); 

var query = @"IF EXISTS 
              (
              SELECT * 
              FROM tempdb.dbo.sysobjects 
              WHERE ID = OBJECT_ID(N'tempdb..##" + tableName + @"') 
              ) 
               BEGIN 
                DELETE FROM ##" + tableName + @" 
               END 
              ELSE 
               BEGIN 
                CREATE TABLE ##" + tableName + @" 
                (ID int) 
               END " + inserts; 

      var command = new SqlCommand(query, sqlConnection); 
... 

私はSを使用する必要があります(スタック交換https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect=1#comment78137_44222に)私に言って人を見てきましたので、 QLBulkCopyと私はそれを行う方法を改善すべきだと私は信じて速くなります。だから、誰かが私のSQLBulkCopyコードを改善する方法を提案したり、アプリケーションのパフォーマンスを向上させる優れた挿入ステートメントがあれば教えてください。

+0

?を実行しますか –

+0

これは別のアプリケーションから来る一連のキーになります。私はまだこのリンクをしていない。今のところ、テストのためにいくつかのIDを使って作成した配列です。 – Jenninha

+0

30,000 IDはおそらくどこかのデータベースから来ています。もしそうなら、私はSQLでこれをすべて行う方法を探しています。 –

答えて

11

問題がある可能性がありますlocalTempTable.AcceptChanges();あなたの変更をコミットします。
あなたが次の操作を行う場合、私はそれが最後のタイムれるAcceptChangesが呼び出されたため、それがロードされてから、このデータセットに対して行われたすべての変更をコミットしたり MSDN - DataSet.AcceptChanges

から速く

foreach (var item in ids) 
    { 
     DataRow row = localTempTable.NewRow(); 
     row[0] = item; 
     localTempTable.Rows.Add(row); 

    } 

    localTempTable.AcceptChanges(); 

    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
    { 
     bulkCopy.DestinationTableName = "##" + tableName; 
     bulkCopy.WriteToServer(localTempTable); 

    } 

を実行すると思います。

+0

より速く走った。ありがとう! – Jenninha

4

このコードを自分でStopWatchオブジェクトで実行して時間を測定します。それは遅くなるすべての反復でのAcceptChangesです。

public void MakeTable(string tableName, List<string> ids, SqlConnection connection) 
{ 
    SqlCommand cmd = new SqlCommand("CREATE TABLE ##" + tableName + " (ID int)", connection); 
    cmd.ExecuteNonQuery(); 

    DataTable localTempTable = new DataTable(tableName); 

    DataColumn id = new DataColumn(); 
    id.DataType = System.Type.GetType("System.Int32"); 
    id.ColumnName = "ID"; 
    localTempTable.Columns.Add(id); 

    System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();   

    sw1.Start(); 
    foreach (var item in ids) 
    { 
     DataRow row = localTempTable.NewRow(); 
     row[0] = item; 
     localTempTable.Rows.Add(row); 

    } 
    localTempTable.AcceptChanges(); 
    long temp1 = sw1.ElapsedMilliseconds; 
    sw1.Reset(); 
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection)) 
    { 
     bulkCopy.DestinationTableName = "##" + tableName; 
     bulkCopy.WriteToServer(localTempTable); 

    } 
    long temp2 = sw1.ElapsedMilliseconds; 
} 

結果AccpetChangesは、foreachループ内

enter image description here

であり、それは

enter image description here

ないときの差が3桁:)

0

使用ですそれはさらに速く

の代わりcmd.ExecuteNonQuery(); を実行するには、文字列のリストのデータが最初の場所でから来るん

cmd.ExecuteReader() 
+2

IDataReaderを使用する方がDataTableを実行するよりも優れていますが、 'cmd.ExectuteReader()'を実行することについて間違っている場合は、コードが実際に結果セットを返さないため、 'cmd.ExecuteNonQuery();' 。 –

+0

あなたはそうです、コードを完全に読まなかった – Enfantcool

関連する問題