2013-06-10 26 views
10

Tôi đang cố gắng tìm hiểu cách tôi có thể cải thiện hiệu suất chèn của mình trong bảng tạm thời trong SQL Server bằng cách sử dụng C#. Một số người nói rằng tôi nên sử dụng SQLBulkCopy tuy nhiên tôi phải làm một cái gì đó sai vì nó có vẻ làm việc chậm hơn nhiều so với việc xây dựng một chuỗi chèn SQL thay thế.Cách nhanh nhất để chèn 30 nghìn hàng trong bảng tạm thời trên Máy chủ SQL với C#

Mã của tôi để tạo ra bảng sử dụng SqlBulkCopy là dưới đây:

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

     } 
    } 

Bằng cách này chèn của tôi mất nhiều thời gian để chạy. Tôi đã chèn của tôi để làm việc nhanh hơn theo cách khác:

Tôi tạo ra các bit chèn như là một chuỗi và gia nhập nó trong SQL của tôi tạo ra tạm thời bảng tuyên bố:

Tạo chèn chuỗi:

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; 

    } 

sử dụng chúng trong các câu lệnh SQL sau khi tạo truy vấn:

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

kể từ khi tôi đã nhìn thấy người nói với tôi (trên stack trao đổi https://dba.stackexchange.com/questions/44217/fastest-way-to-insert-30-thousand-rows-in-sql-server/44222?noredirect=1#comment78137_44222) Rằng tôi nên sử dụng S QLBulkCopy và điều đó sẽ nhanh hơn tôi tin rằng tôi nên cải thiện cách tôi làm điều đó. Vì vậy, nếu bất cứ ai có thể đề nghị làm thế nào tôi có thể cải thiện mã SQLBulkCopy của tôi HOẶC cho tôi biết nếu có một tuyên bố chèn tốt hơn có thể cải thiện hiệu suất của ứng dụng của tôi mà sẽ là tuyệt vời.

+0

đâu dữ liệu cho danh sách này của chuỗi đến từ ở nơi đầu tiên? –

+0

Nó sẽ là một tập hợp các khóa sẽ đến từ một ứng dụng khác. Tôi chưa thực hiện liên kết này.Bây giờ nó là một mảng mà tôi tạo ra với một số id để kiểm tra. – Jenninha

+0

30.000 id có thể đến từ một cơ sở dữ liệu ở đâu đó. Nếu vậy, tôi sẽ tìm kiếm một cách để làm tất cả điều này với sql. –

Trả lời

11

Sự cố của bạn có thể ở localTempTable.AcceptChanges(); Vì nó cam kết thay đổi của bạn.
Nếu bạn làm như sau, tôi nghĩ rằng nó sẽ chạy nhanh hơn

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

    } 

Từ MSDN - DataSet.AcceptChanges

cam kết tất cả các thay đổi được thực to DataSet này vì nó đã được nạp hoặc kể từ khi AcceptChanges lần cuối cùng được gọi là .

+0

Nó đã chạy nhanh hơn. Cảm ơn! – Jenninha

4

Tôi tự chạy mã này với các đối tượng StopWatch để đo thời gian. Đó là AcceptChanges trong mỗi lần lặp lại mà làm chậm.

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

quả khi AccpetChanges là bên trong vòng lặp foreach

enter image description here

Và khi nó không phải

enter image description here

khác biệt là 3 bậc độ lớn :)

0

Sử dụng IDataReader và nó sẽ chạy nhanh hơn

thay vì cmd.ExecuteNonQuery(); Execute

cmd.ExecuteReader() 
+2

Bạn có quyền sử dụng IDataReader tốt hơn là làm một DataTable nhưng bạn không chính xác về việc thực hiện 'cmd.ExectuteReader()', nó vẫn nên là 'cmd.ExecuteNonQuery();' vì mã không thực sự trả về bất kỳ tập kết quả nào . –

+0

Bạn nói đúng, không đọc mã hoàn toàn – Enfantcool

Các vấn đề liên quan