[转]SQL Server 批量插入数据的两种方法

原文地址: http://blog.csdn.net/tjvictor/article/details/4360030

   在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题。下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters)。

运行下面的脚本,建立测试数据库和表值参数。

[c-sharp] 
1.--Create DataBase 2.create database BulkTestDB; 3.go 4.use BulkTestDB; 5.go 6.--Create Table 7.Create table BulkTestTable( 8.Id int primary key, 9.UserName nvarchar(32), 10.Pwd varchar(16)) 11.go 12.--Create Table Valued 13.CREATE TYPE BulkUdt AS TABLE 14. (Id int, 15. UserName nvarchar(32), 16. Pwd varchar(16))

下面我们使用最简单的Insert语句来插入100万条数据,代码如下:

[c-sharp] view plaincopyprint?
1.Stopwatch sw = new Stopwatch();  
2.  
3.SqlConnection sqlConn = new SqlConnection(  
4.    ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);//连接数据库  
5.  
6.SqlCommand sqlComm = new SqlCommand();  
7.sqlComm.CommandText = string.Format("insert into BulkTestTable(Id,UserName,Pwd)values(@p0,@p1,@p2)");//参数化SQL  
8.sqlComm.Parameters.Add("@p0", SqlDbType.Int);  
9.sqlComm.Parameters.Add("@p1", SqlDbType.NVarChar);  
10.sqlComm.Parameters.Add("@p2", SqlDbType.VarChar);  
11.sqlComm.CommandType = CommandType.Text;  
12.sqlComm.Connection = sqlConn;  
13.sqlConn.Open();  
14.try  
15.{  
16.    //循环插入100万条数据,每次插入10万条,插入10次。  
17.    for (int multiply = 0; multiply < 10; multiply++)  
18.    {  
19.        for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)  
20.        {  
21.  
22.            sqlComm.Parameters["@p0"].Value = count;  
23.            sqlComm.Parameters["@p1"].Value = string.Format("User-{0}", count * multiply);  
24.            sqlComm.Parameters["@p2"].Value = string.Format("Pwd-{0}", count * multiply);  
25.            sw.Start();  
26.            sqlComm.ExecuteNonQuery();  
27.            sw.Stop();  
28.        }  
29.        //每插入10万条数据后,显示此次插入所用时间  
30.        Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));  
31.    }  
32.}  
33.catch (Exception ex)  
34.{  
35.    throw ex;  
36.}  
37.finally  
38.{  
39.    sqlConn.Close();  
40.}  
41.  
42.Console.ReadLine();  

耗时图如下:

使用Insert语句插入10万数据的耗时图

由于运行过慢,才插入10万条就耗时72390 milliseconds,所以我就手动强行停止了。

 

下面看一下使用Bulk插入的情况:

bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库

代码如下:

[c-sharp]
1.publicstaticvoid BulkToDB(DataTable dt)  
2.{  
3.    SqlConnection sqlConn = new SqlConnection(  
4.        ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);  
5.    SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConn);  
6.    bulkCopy.DestinationTableName = "BulkTestTable";  
7.    bulkCopy.BatchSize = dt.Rows.Count;  
8.  
9.    try  
10.    {  
11.        sqlConn.Open();  
12.    if (dt != null && dt.Rows.Count != 0)  
13.        bulkCopy.WriteToServer(dt);  
14.    }  
15.    catch (Exception ex)  
16.    {  
17.        throw ex;  
18.    }  
19.    finally  
20.    {  
21.        sqlConn.Close();  
22.        if (bulkCopy != null)  
23.            bulkCopy.Close();  
24.    }  
25.}  
26.  
27.publicstatic DataTable GetTableSchema()  
28.{  
29.    DataTable dt = new DataTable();  
30.    dt.Columns.AddRange(new DataColumn[]{  
31.        new DataColumn("Id",typeof(int)),  
32.        new DataColumn("UserName",typeof(string)),  
33.    new DataColumn("Pwd",typeof(string))});  
34.  
35.    return dt;  
36.}  
37.  
38.staticvoid Main(string[] args)  
39.{  
40.    Stopwatch sw = new Stopwatch();  
41.    for (int multiply = 0; multiply < 10; multiply++)  
42.    {  
43.        DataTable dt = Bulk.GetTableSchema();  
44.        for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)  
45.        {  
46.            DataRow r = dt.NewRow();  
47.            r[0] = count;  
48.            r[1] = string.Format("User-{0}", count * multiply);  
49.            r[2] = string.Format("Pwd-{0}", count * multiply);  
50.            dt.Rows.Add(r);  
51.        }  
52.        sw.Start();  
53.        Bulk.BulkToDB(dt);  
54.        sw.Stop();  
55.        Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));  
56.    }  
57.  
58.    Console.ReadLine();  
59.}  


耗时图如下:

使用Bulk插入100万数据的耗时图

可见,使用Bulk后,效率和性能明显上升。使用Insert插入10万数据耗时72390,而现在使用Bulk插入100万数据才耗时17583。

 

最后再看看使用表值参数的效率,会另你大为惊讶的。

 

表值参数是SQL Server 2008新特性,简称TVPs。对于表值参数不熟悉的朋友,可以参考最新的book online,我也会另外写一篇关于表值参数的博客,不过此次不对表值参数的概念做过多的介绍。言归正传,看代码:

[c-sharp]
1.publicstaticvoid TableValuedToDB(DataTable dt)  
2.{  
3.    SqlConnection sqlConn = new SqlConnection(  
4.      ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);  
5.    conststring TSqlStatement =  
6.     "insert into BulkTestTable (Id,UserName,Pwd)" +  
7.     " SELECT nc.Id, nc.UserName,nc.Pwd" +  
8.     " FROM @NewBulkTestTvp AS nc";  
9.    SqlCommand cmd = new SqlCommand(TSqlStatement, sqlConn);  
10.    SqlParameter catParam = cmd.Parameters.AddWithValue("@NewBulkTestTvp", dt);  
11.    catParam.SqlDbType = SqlDbType.Structured;  
12.    //表值参数的名字叫BulkUdt,在上面的建立测试环境的SQL中有。  
13.    catParam.TypeName = "dbo.BulkUdt";  
14.    try  
15.    {  
16.      sqlConn.Open();  
17.      if (dt != null && dt.Rows.Count != 0)  
18.      {  
19.          cmd.ExecuteNonQuery();  
20.      }  
21.    }  
22.    catch (Exception ex)  
23.    {  
24.      throw ex;  
25.    }  
26.    finally  
27.    {  
28.      sqlConn.Close();  
29.    }  
30.}  
31.  
32.publicstatic DataTable GetTableSchema()  
33.{  
34.    DataTable dt = new DataTable();  
35.    dt.Columns.AddRange(new DataColumn[]{  
36.      new DataColumn("Id",typeof(int)),  
37.      new DataColumn("UserName",typeof(string)),  
38.      new DataColumn("Pwd",typeof(string))});  
39.  
40.    return dt;  
41.}  
42.  
43.staticvoid Main(string[] args)  
44.{  
45.    Stopwatch sw = new Stopwatch();  
46.    for (int multiply = 0; multiply < 10; multiply++)  
47.    {  
48.        DataTable dt = TableValued.GetTableSchema();  
49.        for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)  
50.        {          
51.            DataRow r = dt.NewRow();  
52.            r[0] = count;  
53.            r[1] = string.Format("User-{0}", count * multiply);  
54.            r[2] = string.Format("Pwd-{0}", count * multiply);  
55.            dt.Rows.Add(r);  
56.        }  
57.        sw.Start();  
58.        TableValued.TableValuedToDB(dt);  
59.        sw.Stop();  
60.        Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));  
61.    }  
62.  
63.    Console.ReadLine();  
64.}  

 

 

耗时图如下:

使用表值参数插入100万数据的耗时图

比Bulk还快5秒。

posted on 2013-10-07 12:24  Larryzhi  阅读(129)  评论(0)    收藏  举报

导航