ADO.NET- 中批量添加數據的幾種實現方法比較


在.Net中經常會遇到批量添加數據,如將Excel中的數據導入數據庫,直接在DataGridView控件中添加數據再保存到數據庫等等。

方法一:一條一條循環添加

通常我們的第一反應是采用for或foreach循環一條一條的添加。這樣的方法可想而知,效率肯定很低,可以慢到操作人員無法接受的那種。經過測試(局域網),1W條數據將會耗時3分42秒842毫秒

for (int i = 0; i < dgv.Rows.Count; i++)
{
    string sql  = "insert into .....";
    SqlHelper.ExcuteNonQuery(CommandType.Text, sql, null);
}

 

方法二:每一千條循環添加

也許馬上會有人想到Insert多條記錄,即"Insert into TableName Values(' ',' ',' '),Values(' ',' ',' ')",這種方法在一定程度上提高不少的效率,但是這種方法有幾個弊端。比如說,在SQL Server 2000中它就不支持這種語法,會提示"第 2 行: ',' 附近有語法錯誤。"的警告,批量操作也就無從談起。再比如,這種方法么次最多也只能Insert 1000條數據,如果超過了1000條就會報錯:"INSERT 語句中行值表達式的數目超出了 1000 行值的最大允許值。"。當然了,我們可以分為幾次,每次添加一千條數據,這樣還是比方法一的效率高不少。經過測試(局域網),1W條數據將會耗時0分14秒766毫秒

int rowCount = dataGridView1.Rows.Count;
int quotient = rowCount / 1000;  //
int remainder = rowCount % 1000;  //余數
StringBuilder str = new StringBuilder();         
for (int j = 0; j < quotient; j++)
{
    str.Append("insert into BatchTable values");
    for (int i = 0; i < 1000; i++)
    {
        str.AppendFormat("('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}'),"
            , dataGridView1[0, i].Value, dataGridView1[1, i].Value, dataGridView1[2, i].Value, dataGridView1[3, i].Value,
            dataGridView1[4, i].Value , dataGridView1[5, i].Value, dataGridView1[6, i].Value, dataGridView1[7, i].Value, 
            dataGridView1[8, i].Value, dataGridView1[9, i].Value, dataGridView1[10, i].Value);
    } 
    string sql = str.ToString().TrimEnd(',');
    SqlHelper.ExcuteNonQuery(CommandType.Text, sql, null);
    str.Clear();
}
if (remainder > 0)
{
    str.Append("insert into BatchTable values");
    for (int i = 0; i < remainder; i++)
    {
        str.AppendFormat("('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}'),"
            , dataGridView1[0, i].Value, dataGridView1[1, i].Value, dataGridView1[2, i].Value, dataGridView1[3, i].Value 
            , dataGridView1[4, i].Value, dataGridView1[5, i].Value, dataGridView1[6, i].Value, dataGridView1[7, i].Value,
            dataGridView1[8, i].Value, dataGridView1[9, i].Value, dataGridView1[10, i].Value);
    }
    string sql = str.ToString().TrimEnd(',');
    SqlHelper.ExcuteNonQuery(CommandType.Text, sql, null);
    str.Clear();
}

 

方法三:使用SqlBulkCopy類批量添加數據

SqlBulkCopy類位於System.Data.SqlClient命名空間下,摘自MSDN:Microsoft SQL Server 提供一個稱為 bcp 的流行的命令提示符實用工具,用於將數據從一個表移動到另一個表(表既可以在同一個服務器上,也可以在不同服務器上)。SqlBulkCopy 類允許編寫提供類似功能的托管代碼解決方案。還有其他將數據加載到 SQL Server 表的方法(例如 INSERT 語句),但相比之下SqlBulkCopy 提供明顯的性能優勢。使用 SqlBulkCopy 類只能向 SQL Server 表寫入數據。但是,數據源不限於 SQL Server;可以使用任何數據源,只要數據可加載到 DataTable 實例或可使用IDataReader 實例讀取數據。

采用 SqlBulkCopy類進行批量添加數據將會大大調高效率。經過測試(局域網),1W條數據將會耗時0分0秒292毫秒

public static bool ExcuteNonQuery(DataTable dt)
{
    SqlConnection connection = new SqlConnection(connString);
    connection.Open();
    SqlBulkCopy sqlbulkcopy = new SqlBulkCopy(connection);
    sqlbulkcopy.BulkCopyTimeout = 100;  //超時之前操作完成所允許的秒數
    sqlbulkcopy.BatchSize = dt.Rows.Count;  //每一批次中的行數
    sqlbulkcopy.DestinationTableName = dt.TableName;  //服務器上目標表的名稱
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        sqlbulkcopy.ColumnMappings.Add(i, i);  //映射定義數據源中的列和目標表中的列之間的關系
    }
    sqlbulkcopy.WriteToServer(dt);  // 將DataTable數據上傳到數據表中
    connection.Close();
    return true;
}

 

方法四:利用SQL Server 2008新特性:表值參數,簡稱TVPS

MSDN中對表值參數的解釋:

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

       注意:無法在表值參數中返回數據。 表值參數是只可輸入的參數;不支持 OUTPUT 關鍵字。詳情請參見MSDN

 在ADO.NET中使用表值參數傳遞DataTable對象

1、創建數據表對應的表值參數類型,此類型應與數據表結構一致,假如創建數據表的sql語句為

--BatchTable為數據表名稱
create table [dbo].[BatchTable](
    [Gradation] [nvarchar](10) NULL,
    [Column1] [nvarchar](10) NULL,
    [Column2] [nvarchar](10) NULL,
    [Column3] [nvarchar](10) NULL,
    [Column4] [nvarchar](10) NULL,
    [Column5] [nvarchar](10) NULL,
    [Column6] [nvarchar](10) NULL,
    [Column7] [nvarchar](10) NULL,
    [Column8] [nvarchar](10) NULL,
    [Column9] [nvarchar](10) NULL,
    [Column10] [nvarchar](10) NULL
) ON [PRIMARY]
GO

2、那么對應的創建表值參數類型的語句為

--BatchTableTvps為參數類型名稱
Create type BatchTableTvps as Table  
(  
[Gradation] [nvarchar](10) NULL,
    [Column1] [nvarchar](10) NULL,
    [Column2] [nvarchar](10) NULL,
    [Column3] [nvarchar](10) NULL,
    [Column4] [nvarchar](10) NULL,
    [Column5] [nvarchar](10) NULL,
    [Column6] [nvarchar](10) NULL,
    [Column7] [nvarchar](10) NULL,
    [Column8] [nvarchar](10) NULL,
    [Column9] [nvarchar](10) NULL,
    [Column10] [nvarchar](10) NULL
) 
GO

懶人們一般的做法都是,選中要操作的數據表,單擊右鍵 —> 編寫表腳本為 —> Create到 —> 新查詢編輯器窗口。然后稍稍修改就行了
3、然后就可以在C#中指定SqlParameter參數對象的屬性TypeName為剛剛創建的表值參數類型。

DataTable table = GetDataTable("BatchTable"); //要插入的表
string sql = "insert into BatchTable select * from @BatchTable";
SqlParameter par = new SqlParameter("@BatchTable", SqlDbType.Structured);
par.TypeName = "BatchTableTvps"; //指定表值參數類型
par.Value = table;
SqlParameter[] pars = new SqlParameter[] { par };
int values = SqlHelper.ExcuteNonQuery(CommandType.Text, sql, pars);

 

SqlBulkCopy類批量添加數據與表值參數TVPS批量添加數據比較

同一環境下,添加1W條數據:SqlBulkCopy耗時292毫秒,TVPS耗時902毫秒

同一環境下,添加10W條數據:SqlBulkCopy耗時5秒768毫秒,TVPS耗時6秒617毫秒

同一環境下,添加20W條數據:SqlBulkCopy耗時11秒791毫秒,TVPS耗時16秒525毫秒

測試源碼下載鏈接http://download.csdn.net/detail/tracine0513/8060011


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM