C#

2013-06-10 20 views
10

SQL Server'da geçici bir tabloda 30 bin satır eklemek için en hızlı yolu Ekleme performansımı, SQL Server'da C# kullanarak geçici bir tabloda nasıl geliştirebileceğimi bulmaya çalışıyorum. Bazı insanlar SQLBulkCopy kullanmam gerektiğini söylüyorlar, ancak yanlış bir şey yapmam gerekiyor, çünkü bunun yerine bir SQL insert dizgisi oluşturmaktan çok daha yavaş çalışıyor gibi görünüyor.C#

Kodum SqlBulkCopy altındadır kullanarak tablo oluşturmak için:

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); 

     } 
    } 

benim ekler çalışması uzun zaman alabilir bu şekilde.

Ben bir dize olarak ekler bit oluşturulan ve geçici tablo deyimi oluşturmak benim SQL it katıldı: Başka bir şekilde daha hızlı çalışmak benim ekler var ekler dize

Oluşturma:

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; 

    } 

yaratma sorgusunun ardından SQL deyiminde bunları kullanma:

insanların benim S kullanmalıdır O (yığın alışverişi https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect=1#comment78137_44222 üzerine) bana gördüğüm yana
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); 
... 

QLBulkCopy ve bu daha hızlı olurdu Ben bunu yaptığım şekilde geliştirmem gerektiğine inanıyorum. Herkes SQLBulkCopy kodumu nasıl geliştirebileceğimi önerebilirse VEYA uygulamanızın performansını mükemmelleştirebilecek daha iyi bir ekleme ifadesi olup olmadığını söylerse.

+0

Yürütme çalışacak? –

+0

Başka bir uygulamadan gelecek bir anahtar kümesi olacaktır. Bu bağlantıyı henüz yapmadım.Şimdilik test için bazı kimliklerle oluşturduğum bir dizi. – Jenninha

+0

30.000 kimlik büyük olasılıkla bir veritabanından geliyor. Eğer öyleyse, tüm bunları sql ile yapmak için bir yol arıyordum. –

cevap

11

Sorununuz, değişikliklerinizi taahhüt ettiğinden beri localTempTable.AcceptChanges(); olabilir. Bir sonraki yaparsanız
, o denilen yüklenmiş veya son kez AcceptChanges beri beri bu

hızlı

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); 

    } 

itibaren MSDN - DataSet.AcceptChanges bu DataSet yapılan tüm değişiklikleri Commits çalışacağını düşünüyorum .

+0

Daha hızlı çalıştı. Teşekkürler! – Jenninha

4

Zamanı ölçmek için bu kodu kendim StopWatch nesneleriyle çalıştırıyorum. Her yinelemede AcceptChanges yavaş ilerliyor. AccpetChanges foreach döngüsü

enter image description here

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; 
} 

Sonucu olduğunda Ve olmadığı zaman

enter image description here

Fark :)

0

Kullanımbüyüklük 3 emirdirve dizeleri bu listeye ilişkin veriler ilk etapta geliyor Nerede

yerine cmd.ExecuteNonQuery(); bile daha hızlı

cmd.ExecuteReader() 
+2

Bir IDataReader kullanmak bir DataTable yapmaktan daha iyidir, ancak cmd.ExectuteReader() 'yapmaktan yanlışsınız demektir, hala cmd.ExecuteNonQuery(); olması gerekir, çünkü kod aslında herhangi bir sonuç kümesini döndürmez . –

+0

Haklısın, kodu tamamen okumadım – Enfantcool