[.Net] 使用 SqlBulkCopy 增進批次處理資料效能.

使用套件SqlBulkCopy 有效率地將其他來源的資料大量載入 SQL Server 資料表.

最近維護專案, 看到前輩使用SqlBulkCopy , 大概知道是對DB做資料存取的,  如果只是一般的資料存取用 SqlCommand.ExecuteNonQuery 一筆一筆做掉不就好了嗎??

後來查詢了一下MSDN, 如下:

  類別 描述
System_CAPS_pubclass SqlBulkCopy

可讓您有效率地大量載入具有另一個來源的資料之 SQL Server 資料表。

 

若需要批次更新大筆資料的時候使用此套建可以大幅增進效能.

這也是微軟家的東西,

命名空間:   System.Data.SqlClient
組件:  System.Data (在 System.Data.dll 中)

請安心服用.

簡單的程式範例如下:

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Data.SqlClient;
using System.Transactions;

public partial class test_sqlBulkCopy : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {

  }

  protected void Button1_Click(object sender, EventArgs e)
  {
      //產生source table
      DataTable sourceDt = new DataTable();
      sourceDt.Columns.Add("id", typeof(int));
      sourceDt.Columns.Add("colA", typeof(string));
      sourceDt.Columns.Add("colB", typeof(string));
      sourceDt.Columns.Add("colC", typeof(string));

      //看你要產生幾筆row先寫在datatable
      for (int i = 0; i < 100; i++)
      {
          DataRow dr = sourceDt.NewRow();
          dr["colA"] = "a" + i.ToString();
          dr["colB"] = "b" + i.ToString();
          dr["colC"] = "c" + i.ToString();
          sourceDt.Rows.Add(dr);
      }

      //加入2.0以後的交易,記得匯入System.Transactions.dll
      using (TransactionScope myScope = new TransactionScope())
      {
          //大量寫入
          using (SqlConnection myConn = new SqlConnection(ConfigurationManager.
              ConnectionStrings["NORTHWNDConnectionString"].ConnectionString))
          {
              myConn.Open();

              using (SqlBulkCopy testSbc = new SqlBulkCopy(myConn))
              {
                  //設定
                  testSbc.BatchSize = 1000;
                  testSbc.BulkCopyTimeout = 60;

                  //處理完委派事件,可寫可不寫,在複製過程會觸發testSbc_SqlRowsCopied事件,主要目的是顯示訊息讓使用者了解目前的進度。
                  testSbc.NotifyAfter = sourceDt.Rows.Count;
                  testSbc.SqlRowsCopied += new SqlRowsCopiedEventHandler(testSbc_SqlRowsCopied);

                  //更新資料庫名稱
                  testSbc.DestinationTableName = "dbo.test";

                  //column對應
                  testSbc.ColumnMappings.Add("id", "id");
                  testSbc.ColumnMappings.Add("colA", "a");
                  testSbc.ColumnMappings.Add("colB", "b");
                  testSbc.ColumnMappings.Add("colC", "c");

                  //寫入資料
                  testSbc.WriteToServer(sourceDt);

                  //完成交易
                  myScope.Complete();
              }
          }
      }
  }
  void testSbc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
  {
      ClientScript.RegisterStartupScript(GetType(), "test", "alert('完成');", true);
  }
}

據說若兩邊連線沒有異常, DB本身loading也沒有爆炸, 幾十萬筆資料可以一秒內就跑完.

用了很久才發現他是很不錯的東西呀. 筆記先.

 

參考:

https://msdn.microsoft.com/zh-tw/library/system.data.sqlclient.sqlbulkcopy(v=vs.110).aspx

http://msdn2.microsoft.com/zh-tw/library/system.data.sqlclient.sqlbulkcopy(VS.80).aspx

http://msdn2.microsoft.com/zh-tw/library/system.transactions.transactionscope.aspx