转:SQL Server 批量插入数据的两种方法
在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题。下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters)。
运行下面的脚本,建立测试数据库和表值参数。
- --Create DataBase
- create database BulkTestDB;
- go
- use BulkTestDB;
- go
- --Create Table
- Create table BulkTestTable(
- Id int primary key,
- UserName nvarchar(32),
- Pwd varchar(16))
- go
- --Create Table Valued
- CREATE TYPE BulkUdt AS TABLE
- (Id int,
- UserName nvarchar(32),
- Pwd varchar(16))
下面我们使用最简单的Insert语句来插入100万条数据,代码如下:
- Stopwatch sw = new Stopwatch();
- SqlConnection sqlConn = new SqlConnection(
- ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);//连接数据库
- SqlCommand sqlComm = new SqlCommand();
- sqlComm.CommandText = string.Format("insert into BulkTestTable(Id,UserName,Pwd)values(@p0,@p1,@p2)");//参数化SQL
- sqlComm.Parameters.Add("@p0", SqlDbType.Int);
- sqlComm.Parameters.Add("@p1", SqlDbType.NVarChar);
- sqlComm.Parameters.Add("@p2", SqlDbType.VarChar);
- sqlComm.CommandType = CommandType.Text;
- sqlComm.Connection = sqlConn;
- sqlConn.Open();
- try
- {
- //循环插入100万条数据,每次插入10万条,插入10次。
- for (int multiply = 0; multiply < 10; multiply++)
- {
- for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
- {
- sqlComm.Parameters["@p0"].Value = count;
- sqlComm.Parameters["@p1"].Value = string.Format("User-{0}", count * multiply);
- sqlComm.Parameters["@p2"].Value = string.Format("Pwd-{0}", count * multiply);
- sw.Start();
- sqlComm.ExecuteNonQuery();
- sw.Stop();
- }
- //每插入10万条数据后,显示此次插入所用时间
- Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- sqlConn.Close();
- }
- Console.ReadLine();
耗时图如下:

由于运行过慢,才插入10万条就耗时72390 milliseconds,所以我就手动强行停止了。
下面看一下使用Bulk插入的情况:
bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库
代码如下:
- public static void BulkToDB(DataTable dt)
- {
- SqlConnection sqlConn = new SqlConnection(
- ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);
- SqlBulkCopy bulkCopy = new SqlBulkCopy(sqlConn);
- bulkCopy.DestinationTableName = "BulkTestTable";
- bulkCopy.BatchSize = dt.Rows.Count;
- try
- {
- sqlConn.Open();
- if (dt != null && dt.Rows.Count != 0)
- bulkCopy.WriteToServer(dt);
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- sqlConn.Close();
- if (bulkCopy != null)
- bulkCopy.Close();
- }
- }
- public static DataTable GetTableSchema()
- {
- DataTable dt = new DataTable();
- dt.Columns.AddRange(new DataColumn[]{
- new DataColumn("Id",typeof(int)),
- new DataColumn("UserName",typeof(string)),
- new DataColumn("Pwd",typeof(string))});
- return dt;
- }
- static void Main(string[] args)
- {
- Stopwatch sw = new Stopwatch();
- for (int multiply = 0; multiply < 10; multiply++)
- {
- DataTable dt = Bulk.GetTableSchema();
- for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
- {
- DataRow r = dt.NewRow();
- r[0] = count;
- r[1] = string.Format("User-{0}", count * multiply);
- r[2] = string.Format("Pwd-{0}", count * multiply);
- dt.Rows.Add(r);
- }
- sw.Start();
- Bulk.BulkToDB(dt);
- sw.Stop();
- Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
- }
- Console.ReadLine();
- }
耗时图如下:

可见,使用Bulk后,效率和性能明显上升。使用Insert插入10万数据耗时72390,而现在使用Bulk插入100万数据才耗时17583。
最后再看看使用表值参数的效率,会另你大为惊讶的。
表值参数是SQL Server 2008新特性,简称TVPs。对于表值参数不熟悉的朋友,可以参考最新的book online,我也会另外写一篇关于表值参数的博客,不过此次不对表值参数的概念做过多的介绍。言归正传,看代码:
- public static void TableValuedToDB(DataTable dt)
- {
- SqlConnection sqlConn = new SqlConnection(
- ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString);
- const string TSqlStatement =
- "insert into BulkTestTable (Id,UserName,Pwd)" +
- " SELECT nc.Id, nc.UserName,nc.Pwd" +
- " FROM @NewBulkTestTvp AS nc";
- SqlCommand cmd = new SqlCommand(TSqlStatement, sqlConn);
- SqlParameter catParam = cmd.Parameters.AddWithValue("@NewBulkTestTvp", dt);
- catParam.SqlDbType = SqlDbType.Structured;
- //表值参数的名字叫BulkUdt,在上面的建立测试环境的SQL中有。
- catParam.TypeName = "dbo.BulkUdt";
- try
- {
- sqlConn.Open();
- if (dt != null && dt.Rows.Count != 0)
- {
- cmd.ExecuteNonQuery();
- }
- }
- catch (Exception ex)
- {
- throw ex;
- }
- finally
- {
- sqlConn.Close();
- }
- }
- public static DataTable GetTableSchema()
- {
- DataTable dt = new DataTable();
- dt.Columns.AddRange(new DataColumn[]{
- new DataColumn("Id",typeof(int)),
- new DataColumn("UserName",typeof(string)),
- new DataColumn("Pwd",typeof(string))});
- return dt;
- }
- static void Main(string[] args)
- {
- Stopwatch sw = new Stopwatch();
- for (int multiply = 0; multiply < 10; multiply++)
- {
- DataTable dt = TableValued.GetTableSchema();
- for (int count = multiply * 100000; count < (multiply + 1) * 100000; count++)
- {
- DataRow r = dt.NewRow();
- r[0] = count;
- r[1] = string.Format("User-{0}", count * multiply);
- r[2] = string.Format("Pwd-{0}", count * multiply);
- dt.Rows.Add(r);
- }
- sw.Start();
- TableValued.TableValuedToDB(dt);
- sw.Stop();
- Console.WriteLine(string.Format("Elapsed Time is {0} Milliseconds", sw.ElapsedMilliseconds));
- }
- Console.ReadLine();
- }
耗时图如下:

比Bulk还快5秒。
如需转载,请注明此文原创自CSDN TJVictor专栏:http://blog.csdn.net/tjvictor/archive/2009/07/18/4360030.aspx
转:SQL Server 批量插入数据的两种方法的更多相关文章
- SQL Server 批量插入数据的两种方法
在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍 SQL Server支持的两种批 ...
- SQL Server 批量插入数据的两种方法(转)
此文原创自CSDN TJVictor专栏:http://blog.csdn.net/tjvictor/archive/2009/07/18/4360030.aspx 在SQL Server 中插入一条 ...
- SQLServer 批量插入数据的两种方法
SQLServer 批量插入数据的两种方法-发布:dxy 字体:[增加 减小] 类型:转载 在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Ins ...
- SQL 2005批量插入数据的二种方法
SQL 2005批量插入数据的二种方法 Posted on 2010-07-22 18:13 moss_tan_jun 阅读(2635) 评论(2) 编辑 收藏 在SQL Server 中插入一条数据 ...
- SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便
一.Sql Server插入方案介绍 关于 SqlServer 批量插入的方式,有三种比较常用的插入方式,Insert.BatchInsert.SqlBulkCopy,下面我们对比以下三种方案的速度 ...
- MyBatis 批量插入数据的 3 种方法!
批量插入功能是我们日常工作中比较常见的业务功能之一,之前我也写过一篇关于<MyBatis Plus 批量数据插入功能,yyds!>的文章,但评论区的反馈不是很好,主要有两个问题:第一,对 ...
- MySQL批量插入数据的几种方法
最近公司要求测试数据库的性能,就上网查了一些批量插入数据的代码,发现有好几种不同的用法,插入同样数据的耗时也有区别 别的先不说,先上一段代码与君共享 方法一: package com.bigdata; ...
- SQL Server中迁移数据的几种方法
1.通过工具"DTS"的设计器进行导入或者导出 DTS的设计器功能强大,支持多任务,也是可视化界面,容易操作,但知道的人一般不 多,如果只是进行SQL Server数据库中部分表的 ...
- SQL Server 批量插入数据的方法
运行下面的脚本,建立测试数据库和表. --Create DataBase create database BulkTestDB; go use BulkTestDB; go --Create Tabl ...
随机推荐
- mycat读写分离
版本:mycat1.0 只需要读写分离的功能,分库分表的都不需要. 涉及到的配置文件: 1.conf/server.xml 主要配置的是mycat的用户名和密码,mycat的用户名和密码和mys ...
- j2se jndi
http://blog.csdn.net/lldwolf/article/details/2299622 正如你可以看到,从JNDI中检索对象是相当方便,简单.通过使用JNDI来存储配置信息,无状态对 ...
- nigix以及相关
nginx+php的配置 php与nginx整合 http://www.thinkphp.cn/topic/13082.html [入门篇]Nginx + FastCGI 程序(C/C++) 搭建高性 ...
- CentOS 命令随笔
linux下敲命令时:快速删除当前行已经敲的命令: CTR+U 或者 CTR+/ 快速删除当前行刚输入接近鼠标当前位置的单词:CTR+W 以上在XS ...
- 【转】Picasso – Android系统的图片下载和缓存类库
来源:http://blog.chengyunfeng.com/?p=492 另一篇参考:http://blog.csdn.net/xu_fu/article/details/17043231 Pic ...
- Android开发之实用小知识点汇总-2
1.EditText 中将光标移到文字末尾: EditText mEdit = (EditText)this.findViewById(R.id.EditText01); mEdit .setText ...
- awesome awesomeness
Awesome Awesomeness A curated list of amazingly awesome awesomeness.Also available on: Awesome-Aweso ...
- My97 DatePicker使用之自定义事件
参考网站:http://www.my97.net/dp/demo/resource/2.5.asp 自定义事件 如果你需要做一些附加的操作,你也不必担心,日期控件自带的自定义事件可以满足你的需求.此外 ...
- openSession()和getCureentSession()的区别
openSession():永远是打开一个新的session getCureentSession():如果当前环境有session,则取得原来已经存在的session,如果没有,则创建一个新的sess ...
- [POJ 1674] Sorting by Swapping
Sorting by Swapping Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9514 Accepted: 50 ...