MSSQL批量寫入數據方案

近來有一個項目Feature須要有批量寫入數據的場景,正巧整理資料發現本身之前也相似實現的項目,在重構的同時把相關資料作了一個簡單的梳理,方便你們參考。sql

  1. 循環寫入(簡單粗暴,畢業設計就這樣乾的)(不推薦)
  2. Bulk Copy寫入(>1000K 記錄一次性寫入推薦)
  3. 表值參數方式寫入(mssql 2008新特性)(強烈推薦)

     在SQL Server 2008未提供表值參數以前,須要將多行數據傳遞到存儲過程或參數化sql命令咱們通常會採用如下幾個方法:服務器

  1. 使用一系列單參數來表示多個數據列和行中的值。但使用這個方法會受所容許參數數量限制。Sql server 程序最多能夠有2100個參數。服務器必須將這些參數進行再組織成臨時表或表變量再進行後續處理。
  2. 將多個數據增長分隔字符串或序列化爲xml字符串,而後將這些字符回傳服務器。服務器根據解析字符串與xml進行處理。
  3. 將多條寫入語句包裝在一個單條語句當中。這種方式同sqldataadapter當中的update方法的實現邏輯,能夠標識批次處理的個數。不過就算按照包裝多個語句進行批次提交,每一個語句仍然會分別在服務器上執行。(只是節約了請求的次數而已)
  4. 使用BCP實用工具或SqlBulkCopy對象將不少行數據加載到表中。儘管這薦技術很是有效,但不支持服務器處理,除非將數據加載到臨時表或表變量中。

方案一app

做爲早期學習時出鏡率最高的的實現方法我在這裏就不特別說明了,在這裏直接上碼及測試數據:ide

public static void NormalInsertDate(DataTable dt)
        {
            using (var sqlConn = new SqlConnection(_testDataConnectionString))
            {
                var sql = "INSERT INTO Student(Name,Age) VALUES(@Name,@Age)";
                using (var cmd = new SqlCommand(sql, sqlConn))
                {
                    sqlConn.Open();
                    cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
                    cmd.Parameters.Add("@Age", SqlDbType.Int);
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        cmd.Parameters["@Name"].Value = dt.Rows[i]["Name"];
                        cmd.Parameters["@Age"].Value = dt.Rows[i]["Age"];
                        cmd.ExecuteNonQuery();
                    }

                }
            }
        }
View Code

   

圖一爲每次10k條,寫10次共計100k條數據總計15329ms工具

圖二爲每次100k條,寫10次共計1000k條數據總計184395ms學習

方案二測試

做爲早期批量寫入的救星,批量寫入的出鏡指數4顆星。如下爲測試數據:ui

        public static void BulkInsertData(DataTable dt)
        {
            using (var sqlConn = new SqlConnection(_testDataConnectionString))
            {
                using (var bulkCopy = new SqlBulkCopy(sqlConn)
                {
                    DestinationTableName = "Student",
                    BatchSize = dt.Rows.Count
                })
                {
                    sqlConn.Open();
                    bulkCopy.WriteToServer(dt);
                }
            }
        }
View Code

   

圖一爲每次10k條,寫10次共計100k條數據總計1848msspa

圖二爲每次100k條,寫10次共計1000k條數據總計21584ms設計

方案三表值參數方式寫入

表值參數提供一種將客戶端應用程序中的多行數據封送到 SQL Server 的簡單方式,而不須要屢次往返或特殊服務器端邏輯來處理數據。您可使用表值參數來包裝客戶端應用程序中的數據行,並使用單個參數化命令將數據發送到服務器。傳入的數據行存儲在一個表變量中,而後您能夠經過使用 Transact-SQL 對該表變量進行操做。

可使用標準的 Transact-SQL SELECT 語句來訪問表值參數中的列值。表值參數爲強類型,其結構會自動進行驗證。表值參數的大小僅受服務器內存的限制。

注意:表值參數只能是輸入參數,不能做爲輸出參數。

如下爲相關實現:

1.建立表值參數類型(UDT)

USE Test
--CREATE TABLE 
CREATE TABLE Student
(
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(50),
Age INT
)
--create table parameter type
CREATE TYPE StudentUDT AS TABLE
(
Name NVARCHAR(50),
Age INT
)
View Code
public static void TableParameterInsertData(DataTable dt)
{
    using (var sqlConn = new SqlConnection(_testDataConnectionString))
    {
        var sql = "INSERT INTO Student(Name,Age) SELECT Name, Age FROM @StudentTVPS";//在這裏直接訪問表值參數
        using (var cmd = new SqlCommand(sql, sqlConn))
        {
            var catParam = cmd.Parameters.AddWithValue("@StudentTVPS", dt);
            catParam.SqlDbType = SqlDbType.Structured;
            catParam.TypeName = "StudentUDT";//咱們自定義的表值參數類型名稱
            sqlConn.Open();
            cmd.ExecuteNonQuery();
        }
    }
}
View Code

   

圖一爲每次10k條,寫10次共計100k條數據總計390ms

圖二爲每次100k條,寫10次共計1000k條數據總計4451ms

最後咱們再橫向比較一下:

 

就我本機測試的狀況來看,normal=9*bulk=42*tvps

另外我就一次性大量數據寫入對bulk和tvps單獨進行了測試,一次性寫入100K條數據兩種方案基本持平490ms 

       

但在一次性寫入1000K條數據時差距又再次被拉開,bulk=1.5tvps

就測試數據代表bulk在一次性大量寫入依然有不小的優點,畢竟ms就是專門讓他來作這個事情的。

然而也能夠經過tvps進行分範圍寫入的方式,總消耗時間有小幅度改善。

全部呢,有大量數據一次性寫入場景直接使用bulk copy方式吧。他當仁不讓能夠高效完成使命。

若是就一些普通業務批量場景無需考慮直接上TVPS方式。他的效率相對於較以前xml參數,複雜參數實現批量寫入已是數量級的提高。

你絕對值得擁有。

因爲客戶端硬件環境緣由,測試環境應該不能很是精確。因此以上數據僅供參考。

歡迎你們一塊兒分享交流。

附件本機測試硬件環境:i7 4770+128 ssd+8G內存;

相關文章
相關標籤/搜索