最近要做.net关于sql大量插入,找到了sqlbulkcopy(自己google下,应该很多说明了)这个好东西,于是测试下性能,用了三个方法对比:
1)直接用ado.net,for循环N次进行单条插入
2)把N条插入语句拼在一个sql,进行插入
3)直接使用sqlbulkcopy进行插入
代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;using System.Data.SqlClient;using System.Diagnostics;namespace SQLTEST{ class Program { static void Main(string[] args) { //int time = 200; test(20); test(200); test(2000); test(10000); test(50000); Console.ReadLine(); } public static void test(int time){ Stopwatch sp = new Stopwatch(); Console.WriteLine(time + "条数据插入测试"); //测试方法1 { using (SqlConnection sqlcon = new SqlConnection("Data Source=.;Initial Catalog=Test;User ID=sa;Password=??")) { sqlcon.Open(); string singesql = "INSERT INTO [student] ([name],[age])VALUES(‘abc‘,3);"; SqlCommand sqlcommand = new SqlCommand(singesql, sqlcon); //计时开始 sp.Restart(); for (int i = 0; i < time; i++) { sqlcommand.ExecuteNonQuery(); } sp.Stop(); } } Console.WriteLine("方法1:" + sp.ElapsedMilliseconds + "毫秒"); //测试方法2 { using (SqlConnection sqlcon = new SqlConnection("Data Source=.;Initial Catalog=Test;User ID=sa;Password=??")) { sqlcon.Open(); string singesql = "INSERT INTO [student] ([name],[age])VALUES(‘abc‘,3);"; string execsql = ""; for (int i = 0; i < time; i++) { execsql = execsql + singesql; } SqlCommand sqlcommand = new SqlCommand(execsql, sqlcon); //计时开始 sp.Restart(); sqlcommand.ExecuteNonQuery(); sp.Stop(); } } Console.WriteLine("方法2:" + sp.ElapsedMilliseconds + "毫秒"); //测试方法3 { using (SqlConnection sqlcon = new SqlConnection("Data Source=.;Initial Catalog=Test;User ID=sa;Password=??")) { sqlcon.Open(); SqlBulkCopy sqlc = new SqlBulkCopy(sqlcon); DataTable dt = new DataTable(); dt.Columns.Add("id"); dt.Columns.Add("name"); dt.Columns.Add("age"); for (int i = 0; i < time; i++) { dt.Rows.Add(38009, "nemw", 123); } sqlc.DestinationTableName = "student"; //计时开始 sp.Restart(); sqlc.WriteToServer(dt); sp.Stop(); } } Console.WriteLine("方法3:" + sp.ElapsedMilliseconds + "毫秒"); Console.WriteLine(); } }}
插入N条数据的测试结果如下:
效率相差还是很夸张的,大家大量数据插入还是有sqlbulkcopy吧,原理还的高手告知~~
关于SqlBulkCopy的测试
标签:
小编还为您整理了以下内容,可能对您也有帮助:
如何通过SqlBulkCopy实现批量导入数据
1.本文实现在c#中可高效的将excel数据导入到sqlserver数据库中,很多人通过循环来拼接sql,这样做不但容易出错而且效率低下,最好的办法是使用bcp,也就是System.Data.SqlClient.SqlBulkCopy 类来实现。不但速度快,而且代码简单,下面测试代码导入一个6万多条数据的sheet,包括读取(全部读取比较慢)在我的开发环境中只需要10秒左右,而真正的导入过程只需要4.5秒。 2.代码如下: using System; using System.Data; using System.Windows.Forms; using System.Data.OleDb; namespace WindowsApplication2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //测试,将excel中的sheet1导入到sqlserver中 string connString = "server=localhost;uid=sa;pwd=sqlgis;database=master"; System.Windows.Forms.OpenFileDialog fd = new OpenFileDialog(); if (fd.ShowDialog() == DialogResult.OK) { ...
SQL批量插入数据几种方案的性能详细对比
public class DataInertTest 2 { 3 /// <summary> 4 /// 循环插入 5 /// </summary> 6 /// <returns>执行时间(秒)</returns> 7 public double LoopInsert(int count) 8 { 9 StringBuilder sql = new StringBuilder();10 for (int i = 0; i < count; i++)11 {12 sql.Append(" Insert into TQRCode(Name,Remark) values(‘这是第").Append(i).Append("条数据‘,‘这是第").Append(i).Append("条数据_remark‘) ");13 }14 //时间统计15 var stopwatch = new Stopwatch();16 stopwatch.Start();17 new Helper().Excute(sql.ToString());18 return stopwatch.Elapsed.TotalMilliseconds;19 }20 21 /// <summary>22 /// 批量插入23 /// </summary>24 /// <returns>执行时间(秒)</returns>25 public double BatchInsert(int count)26 { 27 StringBuilder sql = new StringBuilder();28 sql.Append(" Insert into TQRCode(Name,Remark) values ");29 for (int i = 0; i < count; i++)30 {31 32 sql.Append(" (‘这是第").Append(i).Append("条数据‘,‘这是第").Append(i).Append("条数据_remark‘) ");33 if (i % 500 == 0)34 { 35 sql.Append(" Insert into TQRCode(Name,Remark) values ");36 }37 else if (i < count - 1)38 {39 sql.Append(",");40 }41 }42 43 //时间统计44 var stopwatch = new Stopwatch();45 stopwatch.Start(); 46 new Helper().Excute(sql.ToString());47 return stopwatch.Elapsed.TotalMilliseconds;48 }49 }C#实现代码
注:sqlserver中单次批量插入数据最多1000条否则会提示我们:The number of row value expressions in the INSERT statement exceeds the maximum allowed number of 1000 row values.
测试代码:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 for (int i = 0; i < 3; i++) 6 { 7 var obj = new DataInertTest(); 8 var t1 = obj.LoopInsert(100000); 9 var t2 = obj.BatchInsert(100000);10 11 Console.WriteLine("LoopInsert : {0}", t1);12 Console.WriteLine("BatchInsert : {0}", t2);13 Console.WriteLine("--------------------------------------------------");14 15 } 16 Console.ReadLine();17 } 18 }测试代码
测试结果:
执行了3次结果很明显,效率差距在10倍以上。批量插入的方式之所以比循环插入快,主要因为sqlserver中每个insert into 都是一个独立的事务,循环插入500条数据就是500个事务,而一次插入500条数据,就只有一个事务。事务减少了消耗自然也就小了。且频繁的事务提交相当影响数据库的性能,也就起到了影响整个系统性能的作用(嘿嘿,一不小心也许服务器就挂了)。
需要注意的是,测试中因为数据量不大所以两种方式都是采用的一次入库的方式,这样做可以减少数据库连接次数。但是这样做有个很大的弊端:内存消耗会很大。10w数据的sql拼接还好,如果是100w行那就未必了。所以,如果单条数据较大,建议每几百或几千行的时候提交一次,这个数字具体多大需要量体裁衣,平衡内存消耗。
SqlServer数据插入性能小记
标签:
SQL批量插入数据几种方案的性能详细对比
public class DataInertTest 2 { 3 /// <summary> 4 /// 循环插入 5 /// </summary> 6 /// <returns>执行时间(秒)</returns> 7 public double LoopInsert(int count) 8 { 9 StringBuilder sql = new StringBuilder();10 for (int i = 0; i < count; i++)11 {12 sql.Append(" Insert into TQRCode(Name,Remark) values(‘这是第").Append(i).Append("条数据‘,‘这是第").Append(i).Append("条数据_remark‘) ");13 }14 //时间统计15 var stopwatch = new Stopwatch();16 stopwatch.Start();17 new Helper().Excute(sql.ToString());18 return stopwatch.Elapsed.TotalMilliseconds;19 }20 21 /// <summary>22 /// 批量插入23 /// </summary>24 /// <returns>执行时间(秒)</returns>25 public double BatchInsert(int count)26 { 27 StringBuilder sql = new StringBuilder();28 sql.Append(" Insert into TQRCode(Name,Remark) values ");29 for (int i = 0; i < count; i++)30 {31 32 sql.Append(" (‘这是第").Append(i).Append("条数据‘,‘这是第").Append(i).Append("条数据_remark‘) ");33 if (i % 500 == 0)34 { 35 sql.Append(" Insert into TQRCode(Name,Remark) values ");36 }37 else if (i < count - 1)38 {39 sql.Append(",");40 }41 }42 43 //时间统计44 var stopwatch = new Stopwatch();45 stopwatch.Start(); 46 new Helper().Excute(sql.ToString());47 return stopwatch.Elapsed.TotalMilliseconds;48 }49 }C#实现代码
注:sqlserver中单次批量插入数据最多1000条否则会提示我们:The number of row value expressions in the INSERT statement exceeds the maximum allowed number of 1000 row values.
测试代码:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 for (int i = 0; i < 3; i++) 6 { 7 var obj = new DataInertTest(); 8 var t1 = obj.LoopInsert(100000); 9 var t2 = obj.BatchInsert(100000);10 11 Console.WriteLine("LoopInsert : {0}", t1);12 Console.WriteLine("BatchInsert : {0}", t2);13 Console.WriteLine("--------------------------------------------------");14 15 } 16 Console.ReadLine();17 } 18 }测试代码
测试结果:
执行了3次结果很明显,效率差距在10倍以上。批量插入的方式之所以比循环插入快,主要因为sqlserver中每个insert into 都是一个独立的事务,循环插入500条数据就是500个事务,而一次插入500条数据,就只有一个事务。事务减少了消耗自然也就小了。且频繁的事务提交相当影响数据库的性能,也就起到了影响整个系统性能的作用(嘿嘿,一不小心也许服务器就挂了)。
需要注意的是,测试中因为数据量不大所以两种方式都是采用的一次入库的方式,这样做可以减少数据库连接次数。但是这样做有个很大的弊端:内存消耗会很大。10w数据的sql拼接还好,如果是100w行那就未必了。所以,如果单条数据较大,建议每几百或几千行的时候提交一次,这个数字具体多大需要量体裁衣,平衡内存消耗。
SqlServer数据插入性能小记
标签:
请教大家SqlBulkCopy能否向多张表插入数据
造一个Datatable存储将要批量导入的数据
DataTable dt = new DataTable();
dt.Columns.Add("Rid", typeof(string));
dt.Columns.Add("Rname", typeof(string));
dt.Columns.Add("Rnumber", typeof(string));
dt.Columns.Add("Rstate", typeof(string));
dt.Columns.Add("isDel", typeof(string));
dt.Columns.Add("Ctime", typeof(DateTime));
dt.Columns.Add("Utime", typeof(DateTime));
// 见识下SqlBulkCopy强悍之处,来个十万条数数据试验
int i;
for (i = 0; i < Convert.ToInt32(drpNum.SelectedValue); i++)
{
DataRow dr = dt.NewRow();
dr["Rid"] = Guid.NewGuid().ToString();
dr["Rname"] = "测试数据" + i.ToString();
dr["Rnumber"] = "i";
dr["Rstate"] = "1";
dr["isDel"] = "1";
dr["Ctime"] = DateTime.Now ;
dr["Utime"] = DateTime.Now;
dt.Rows.Add(dr);
}
string str = ConfigurationManager.ConnectionStrings["conn"].ConnectionString.ToString();
//声明数据库连接
SqlConnection conn = new SqlConnection(str);
conn.Open();
//声明SqlBulkCopy ,using释放非托管资源
请教大家SqlBulkCopy能否向多张表插入数据
造一个Datatable存储将要批量导入的数据
DataTable dt = new DataTable();
dt.Columns.Add("Rid", typeof(string));
dt.Columns.Add("Rname", typeof(string));
dt.Columns.Add("Rnumber", typeof(string));
dt.Columns.Add("Rstate", typeof(string));
dt.Columns.Add("isDel", typeof(string));
dt.Columns.Add("Ctime", typeof(DateTime));
dt.Columns.Add("Utime", typeof(DateTime));
// 见识下SqlBulkCopy强悍之处,来个十万条数数据试验
int i;
for (i = 0; i < Convert.ToInt32(drpNum.SelectedValue); i++)
{
DataRow dr = dt.NewRow();
dr["Rid"] = Guid.NewGuid().ToString();
dr["Rname"] = "测试数据" + i.ToString();
dr["Rnumber"] = "i";
dr["Rstate"] = "1";
dr["isDel"] = "1";
dr["Ctime"] = DateTime.Now ;
dr["Utime"] = DateTime.Now;
dt.Rows.Add(dr);
}
string str = ConfigurationManager.ConnectionStrings["conn"].ConnectionString.ToString();
//声明数据库连接
SqlConnection conn = new SqlConnection(str);
conn.Open();
//声明SqlBulkCopy ,using释放非托管资源
高效Insert数据到sql server里面 C++
有两种方法一种是bulk的方法:
bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库
另外一个是用表值参数。
表值参数是SQL Server 2008新特性,简称TVPs。表值参数有两大优点:一是它不需要为初始的数据加锁,二是它不会导致语句重新编译。
表值参数的创建和使用包括以下步骤:
1) 创建表类型
2) 创建一个可将表类型作为参数来接受的存储过程或函数
3) 创建表变量并插入数据
4) 调用该存储过程和函数,并将表变量作为参数传递。
从测试结果来看用表值参数比用那个bulk还要快一些,你这个1秒100条一点问题都没有。追问嗯 其实你的回答比较符合我的心意 ,但是你这篇文章我倒是看过,但是他都是用C#的类及方法。
有没有C++的方法呢?
多谢
高效Insert数据到sql server里面 C++
有两种方法一种是bulk的方法:
bulk方法主要思想是通过在客户端把数据都缓存在Table中,然后利用SqlBulkCopy一次性把Table中的数据插入到数据库
另外一个是用表值参数。
表值参数是SQL Server 2008新特性,简称TVPs。表值参数有两大优点:一是它不需要为初始的数据加锁,二是它不会导致语句重新编译。
表值参数的创建和使用包括以下步骤:
1) 创建表类型
2) 创建一个可将表类型作为参数来接受的存储过程或函数
3) 创建表变量并插入数据
4) 调用该存储过程和函数,并将表变量作为参数传递。
从测试结果来看用表值参数比用那个bulk还要快一些,你这个1秒100条一点问题都没有。追问嗯 其实你的回答比较符合我的心意 ,但是你这篇文章我倒是看过,但是他都是用C#的类及方法。
有没有C++的方法呢?
多谢
sqlbulkcopy批量导入数据怎么建立映射
实际的开发可能会遇到数据大批量插入数据的问题,若是一条条的循环倒数效率非常低下,这个较好的解决方案
protected void Button1_Click(object sender, EventArgs e)
{
DateTime beginTime = DateTime.Now;
Response.Write("开始时间:" + beginTime.ToString("yyyy年MM月dd日:HH:mm:ss:fff"));
//构造一个Datatable存储将要批量导入的数据
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(string));
dt.Columns.Add("name", typeof(string));
// 见识下SqlBulkCopy强悍之处,来个十万条数数据试验
for ( int i = 0; i < 100000; i++)
{
DataRow dr = dt.NewRow();
dr["name"] = i.ToString();
dt.Rows.Add(dr);
}
string str = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString.ToString(); //声明数据库连接
SqlConnection conn = new SqlConnection(str);
conn.Open();
using (SqlBulkCopy sqlBC = new SqlBulkCopy(conn)) //声明SqlBulkCopy ,using释放非托管资源
{
sqlBC.BatchSize = 1000; //一次批量的插入的数据量
sqlBC.BulkCopyTimeout = 60;//超时之前操作完成所允许的秒数,如果超时则事务不会提交 ,数据将回滚,所有已复制的行都会从目标表中移除
sqlBC.NotifyAfter = 10000; //设定 NotifyAfter 属性,以便在每插入10000 条数据时,呼叫相应事件。
sqlBC.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
sqlBC.DestinationTableName = "dbo.text"; //设置要批量写入的表
//自定义的datatable和数据库的字段进行对应
sqlBC.ColumnMappings.Add("id", "tel");
sqlBC.ColumnMappings.Add("name", "neirong");
sqlBC.WriteToServer(dt); //批量写入
}
conn.Dispose();
Response.Write("<br/>");
DateTime endTime = DateTime.Now;
Response.Write("结束时间:" + endTime.ToString("yyyy年MM月dd日:HH:mm:ss:fff"));
TimeSpan useTime = endTime-beginTime;//使用时间
Response.Write("<br/>插入时间:"+ useTime.TotalSeconds.ToString()+"秒");
}
//响应时事件
void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
{ Response.Write("<br/> OK! "); }
另一个例子
public static int SaveTestLogs(DataTable dtTestLogs)
{
using (SqlBulkCopy sqlcopy = new SqlBulkCopy(SqlHelper.ConnectionStringLocalTransaction))
{
sqlcopy.DestinationTableName = "IQC_MeasureInfo";//目标表的名称
foreach (DataColumn dc in dtTestLogs.Columns)
{
sqlcopy.ColumnMappings.Add(dc.ColumnName, dc.ColumnName);//自定义的DataTable和数据库表的字段相对应
}
sqlcopy.WriteToServer(dtTestLogs);
}
return 1;
}
sqlbulkcopy批量导入数据怎么建立映射
实际的开发可能会遇到数据大批量插入数据的问题,若是一条条的循环倒数效率非常低下,这个较好的解决方案
protected void Button1_Click(object sender, EventArgs e)
{
DateTime beginTime = DateTime.Now;
Response.Write("开始时间:" + beginTime.ToString("yyyy年MM月dd日:HH:mm:ss:fff"));
//构造一个Datatable存储将要批量导入的数据
DataTable dt = new DataTable();
dt.Columns.Add("id", typeof(string));
dt.Columns.Add("name", typeof(string));
// 见识下SqlBulkCopy强悍之处,来个十万条数数据试验
for ( int i = 0; i < 100000; i++)
{
DataRow dr = dt.NewRow();
dr["name"] = i.ToString();
dt.Rows.Add(dr);
}
string str = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString.ToString(); //声明数据库连接
SqlConnection conn = new SqlConnection(str);
conn.Open();
using (SqlBulkCopy sqlBC = new SqlBulkCopy(conn)) //声明SqlBulkCopy ,using释放非托管资源
{
sqlBC.BatchSize = 1000; //一次批量的插入的数据量
sqlBC.BulkCopyTimeout = 60;//超时之前操作完成所允许的秒数,如果超时则事务不会提交 ,数据将回滚,所有已复制的行都会从目标表中移除
sqlBC.NotifyAfter = 10000; //设定 NotifyAfter 属性,以便在每插入10000 条数据时,呼叫相应事件。
sqlBC.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
sqlBC.DestinationTableName = "dbo.text"; //设置要批量写入的表
//自定义的datatable和数据库的字段进行对应
sqlBC.ColumnMappings.Add("id", "tel");
sqlBC.ColumnMappings.Add("name", "neirong");
sqlBC.WriteToServer(dt); //批量写入
}
conn.Dispose();
Response.Write("<br/>");
DateTime endTime = DateTime.Now;
Response.Write("结束时间:" + endTime.ToString("yyyy年MM月dd日:HH:mm:ss:fff"));
TimeSpan useTime = endTime-beginTime;//使用时间
Response.Write("<br/>插入时间:"+ useTime.TotalSeconds.ToString()+"秒");
}
//响应时事件
void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
{ Response.Write("<br/> OK! "); }
另一个例子
public static int SaveTestLogs(DataTable dtTestLogs)
{
using (SqlBulkCopy sqlcopy = new SqlBulkCopy(SqlHelper.ConnectionStringLocalTransaction))
{
sqlcopy.DestinationTableName = "IQC_MeasureInfo";//目标表的名称
foreach (DataColumn dc in dtTestLogs.Columns)
{
sqlcopy.ColumnMappings.Add(dc.ColumnName, dc.ColumnName);//自定义的DataTable和数据库表的字段相对应
}
sqlcopy.WriteToServer(dtTestLogs);
}
return 1;
}
像数据库一次性插入10w条数据,怎么插入效率快啊!
在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题
下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters)。
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();
}
c#sqlbulkcopy 批量写入数据可否回滚
可以,需要使用Transaction登记,给你我以前写的批量导入代码,我稍微修改了一下。
public bool AddDataTableToDB(DataTable MyTable)c#sqlbulkcopy 批量写入数据可否回滚
可以,需要使用Transaction登记,给你我以前写的批量导入代码,我稍微修改了一下。
public bool AddDataTableToDB(DataTable MyTable)SQLServer数据批量导入的几种方式
SQLServer数据批量导入的几种方式
说到SQLServer 的数据批量导入,下面用常用的几种方式做下对比,后面详细介绍每种方式如何使用(本文的代码使用语言c#)
导入方式
是否需写代码
导入过程能否对数据加工
插入数据的速度
多表数据导入
是否必需写SQL语句
1.通过SQLServer客户端管理工具
F
F
快
F
F
2.循环调用插入语句、或存储过程
T
T
慢
T
T
3.使用SqlBulkCopy
T
F
快
F
F
4.使用SQLServer表值参数
T
T
快
T
T
1.通过SQLServer客户端管理工具
打开SQLServer客户端连接要操作的数据库引擎
右键要操作的数据库,选择任务--导入数据,第一次使用会弹出向导页如下图:
点下一步,一般要导入的数据都是excel,数据源我们选择Microsofy Excel(不同版本会有些差异),
浏览选择要导入的excel文件;
下一步选择目标数据源选择我们的SQLServer
根据需要一直点下一步,需要注意在选择表和数据源页面,根据实际需要选择对应的表,以及编辑列的映射,
最后点击完成,导入数据。
2.循环调用插入语句、或存储过程
此方法就是调用写好的sql语句或存储过程来循环的插入数据导数据库;根据需要可以在读取文件数据后,对数据进行校验和加工。
下面代码是一个循环插入的实现,如果需要输出导入进度可以用BackgroundWorker+ progressBar在页面上显示导入进度;
private int DataImport()
{
if (File.Exists(path))
File.Delete(path);
int i = 0;
// 打开数据库连接
string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
SqlConnection Coon = new SqlConnection(strConn);
if (Coon.State.Equals(ConnectionState.Closed))
{
Coon.Open();
}
foreach (DataRow dr in m_dt.Rows)
{
i++;
if (bkWorker.CancellationPending)
{
e.Cancel = true;
return -1;
}
SqlParameter[] parms = {
new SqlParameter("@Name", SqlDbType.VarChar, 32),
new SqlParameter("@Sheng", SqlDbType.VarChar),
new SqlParameter("@City", SqlDbType.VarChar),
new SqlParameter("@Xian", SqlDbType.VarChar)
};
try
{
parms[0].Value = (dr["姓名"] + "").Trim();
parms[7].Value = dr["省"] + "";
parms[8].Value = dr["市"] + "";
parms[9].Value = dr["县"] + "";
}
catch (Exception)
{
MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return -1;
}
try
{
SqlCommand Cmd = Tools.CreateCmd("P_Data_Import", parms, Conn);
int iRet = Cmd.ExecuteNonQuery();
if (iRet == 0)
{
continue;
}
}
catch (Exception ex)
{
Tools.Log_Write("第" + (m_dt.Rows.IndexOf(dr)+1).ToString() + "行导入出错:" + ex.Message, "d:\数据导入日志.txt");
continue;
}
}
if (MessageBox.Show("数据导入完成!,打开导入日志!", "提示") == DialogResult.OK)
{
this.buttonImport.Enabled = true;
if (File.Exists(path))
System.Diagnostics.Process.Start(path);
}
Conn.Close();
return -1;
}
// 打开数据库连接
public static SqlConnection ReturnConn()
{
string strConn = "server=数据库地址;uid=数据库账号;pwd=密码;database=数据库名"
SqlConnection Coon = new SqlConnection(strConn);
if (Coon.State.Equals(ConnectionState.Closed))
{
Coon.Open();
}
return Coon;
}
// 执行带参数的存储过程
public static SqlCommand CreateCmd(string procName, SqlParameter[] prams, SqlConnection Conn)
{
SqlConnection SqlConn = Conn;
if (SqlConn.State.Equals(ConnectionState.Closed))
{
SqlConn.Open();
}
SqlCommand Cmd = new SqlCommand();
Cmd.CommandType = CommandType.StoredProcere;
Cmd.Connection = SqlConn;
Cmd.CommandText = procName;
if (prams != null)
{
foreach (SqlParameter parameter in prams)
{
if (parameter != null)
{
Cmd.Parameters.Add(parameter);
}
}
}
return Cmd;
}
3.使用SqlBulkCopy
下面以导入学生消课数据为例,导入数据的方法,关于SqlBulkCopy(官方解释:允许你使用其他源的数据有效地批量加载 SQL Server 表。)的使用可以到到网上搜索,资料一大堆,官方文档直通通车
首先要构造要导入数据格式的DataTable类型的对象(TransferData)、其次要设置和数据源的列映射关系
Stopwatch 用于计算导入数据耗费时间
private void InsertTwo()
{
OpenFileDialog fd = new OpenFileDialog();
if (fd.ShowDialog() != DialogResult.OK)
{
return;
}
Stopwatch sw = new Stopwatch();
//给datatable 构造Column
DataTable dt = Tools.TransferData(fd.FileName, "sheet1","");
dt.Columns.Add(xhFee);
this.btn_Import.Enabled = false;
string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
using (SqlConnection conn = new SqlConnection(strConn))
{
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
bulkCopy.DestinationTableName = "T_FI_IncomeDetail";
bulkCopy.BatchSize = dt.Rows.Count;
//设置列对应关系
bulkCopy.ColumnMappings.Add("辅导类型", "FdId");
bulkCopy.ColumnMappings.Add("消耗课时或课次", "XhKeshi");
bulkCopy.ColumnMappings.Add("消耗日期", "CreateTime");
bulkCopy.ColumnMappings.Add("学生姓名", "Name");
conn.Open();
sw.Start();
int totalRow = dt.Rows.Count;
if (dt != null && dt.Rows.Count != 0)
{
dateTimeDelete.Value = Convert.ToDateTime(dt.Rows[0]["消耗日期"]);
bulkCopy.WriteToServer(dt);
sw.Stop();
}
MessageBox.Show(string.Format("插入{0}条记录共花费{1}毫秒", totalRow, sw.ElapsedMilliseconds));
}
}
// 获取excel数据并填充到DataTable
public static TransferData(string excelFile, string sheetName,string strScreen)
{
System.Data.DataTable dt = new System.Data.DataTable();
try
{
//获取全部数据
string strConn = "Provider=Microsoft.Ace.Oledb.12.0;Data Source=" + excelFile + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=1;'";
OleDbConnection conn = new OleDbConnection(strConn);
conn.Open();
OleDbDataAdapter myCommand = null;
myCommand = new OleDbDataAdapter("Select * from [Sheet1$] " + strScreen, strConn);
myCommand.Fill(dt);
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return dt;
}
4.使用SQLServer表值参数
该方法对于需要批量导入数据,有需要对数据进行逻辑操作,影响多张表时,尤其实用;本例以导入用户资料为例,亲测由于逻辑复杂在存储过程中使用游标处理2000条数据,2s就可完全导入。
主要是应用了SQLServer的表类型参数,通过给存储过程传入表数据,让sql操作都在数据库中进行,提升操作性能。
首先要根据要在数据库 创建自定义表类型,创建语句格式如下:
CREATE TYPE [dbo].[UserInfo] AS TABLE(
[Name] [varchar](32) NULL,
[Code] [varchar](32) NULL,
[Gender] [varchar](32) NULL,
[Birthday] [datetime] NULL
)
存储过程使用方式:UserInfo即为提前创建好的自定义表类型
create proc procName
(
@DataTable UserInfo readonly
)
as
begin
-- 实现自己的逻辑对@DataTable的使用可以向普通表一样,
-- 建议 如果需要对@DataTable需要连表过滤数据,请使用临时表, 否则可能会提示 超出数据库设置的最大查询时间
--(在数据库引擎,右键属性--连接中可以查看使用查询*器防止查询时间过长,不勾选默认30s),
-- 建议逻辑操作能放在代码中处理的,不要放在存储过程中,为了减小数据库服务器压力
end
代码调用实例:
private int DataImport1(object sender)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string path = "d:\数据导入日志.txt";
if (File.Exists(path))
File.Delete(path);
int count = m_dt.Rows.Count;
SqlConnection Conn = SsZongs.ReturnConn();
DataTable dt = new DataTable("userIfo");
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Gender", typeof(string));
dt.Columns.Add("Birthday", typeof(DateTime));
try
{
for (int i = 0; i < count; i++)
{
try
{
dt.Rows.Add((m_dt.Rows[i]["姓名"] + "").Trim(),
m_dt.Rows[i]["编号"].ToString(),
m_dt.Rows[i]["性别"].ToString(),
m_dt.Rows[i]["出生日期"]
);
}
catch (Exception)
{
MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return -1;
}
}
Tools.insertTableToDB(dt, "procName");
}
catch (Exception ex)
{
Tools.Log_Write(ex.Message, "d:\数据导入日志.txt");
}
finally
{
sw.Stop();
if (MessageBox.Show("数据导入完成!耗时"+ sw.ElapsedMilliseconds + "毫秒,打开导入日志!", "提示") == DialogResult.OK)
{
this.buttonImport.Enabled = true;
if (File.Exists(path))
System.Diagnostics.Process.Start(path);
}
}
return -1;
}
public static void insertTableToDB(System.Data.DataTable dt,string procName)
{
SqlConnection sqlCon = SsZongs.ReturnConn();
using (var cmd = new SqlCommand(procName, sqlCon))
{
cmd.CommandType = CommandType.StoredProcere;
var param = new SqlParameter("@DataTable", SqlDbType.Structured) { Value = dt };
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
sqlCon.Close();
}
总结
以上几种方式,我在实际工作中都有使用, 具体业务还需要根据情况选择合适的方案。
文档编写能力不好,有需要的可以随时交流。
我的掘金
SQLServer数据批量导入的几种方式
标签:elfuse数据库服务器blebatchtail图片ide资料
SQLServer数据批量导入的几种方式
SQLServer数据批量导入的几种方式
说到SQLServer 的数据批量导入,下面用常用的几种方式做下对比,后面详细介绍每种方式如何使用(本文的代码使用语言c#)
导入方式
是否需写代码
导入过程能否对数据加工
插入数据的速度
多表数据导入
是否必需写SQL语句
1.通过SQLServer客户端管理工具
F
F
快
F
F
2.循环调用插入语句、或存储过程
T
T
慢
T
T
3.使用SqlBulkCopy
T
F
快
F
F
4.使用SQLServer表值参数
T
T
快
T
T
1.通过SQLServer客户端管理工具
打开SQLServer客户端连接要操作的数据库引擎
右键要操作的数据库,选择任务--导入数据,第一次使用会弹出向导页如下图:
点下一步,一般要导入的数据都是excel,数据源我们选择Microsofy Excel(不同版本会有些差异),
浏览选择要导入的excel文件;
下一步选择目标数据源选择我们的SQLServer
根据需要一直点下一步,需要注意在选择表和数据源页面,根据实际需要选择对应的表,以及编辑列的映射,
最后点击完成,导入数据。
2.循环调用插入语句、或存储过程
此方法就是调用写好的sql语句或存储过程来循环的插入数据导数据库;根据需要可以在读取文件数据后,对数据进行校验和加工。
下面代码是一个循环插入的实现,如果需要输出导入进度可以用BackgroundWorker+ progressBar在页面上显示导入进度;
private int DataImport()
{
if (File.Exists(path))
File.Delete(path);
int i = 0;
// 打开数据库连接
string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
SqlConnection Coon = new SqlConnection(strConn);
if (Coon.State.Equals(ConnectionState.Closed))
{
Coon.Open();
}
foreach (DataRow dr in m_dt.Rows)
{
i++;
if (bkWorker.CancellationPending)
{
e.Cancel = true;
return -1;
}
SqlParameter[] parms = {
new SqlParameter("@Name", SqlDbType.VarChar, 32),
new SqlParameter("@Sheng", SqlDbType.VarChar),
new SqlParameter("@City", SqlDbType.VarChar),
new SqlParameter("@Xian", SqlDbType.VarChar)
};
try
{
parms[0].Value = (dr["姓名"] + "").Trim();
parms[7].Value = dr["省"] + "";
parms[8].Value = dr["市"] + "";
parms[9].Value = dr["县"] + "";
}
catch (Exception)
{
MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return -1;
}
try
{
SqlCommand Cmd = Tools.CreateCmd("P_Data_Import", parms, Conn);
int iRet = Cmd.ExecuteNonQuery();
if (iRet == 0)
{
continue;
}
}
catch (Exception ex)
{
Tools.Log_Write("第" + (m_dt.Rows.IndexOf(dr)+1).ToString() + "行导入出错:" + ex.Message, "d:\数据导入日志.txt");
continue;
}
}
if (MessageBox.Show("数据导入完成!,打开导入日志!", "提示") == DialogResult.OK)
{
this.buttonImport.Enabled = true;
if (File.Exists(path))
System.Diagnostics.Process.Start(path);
}
Conn.Close();
return -1;
}
// 打开数据库连接
public static SqlConnection ReturnConn()
{
string strConn = "server=数据库地址;uid=数据库账号;pwd=密码;database=数据库名"
SqlConnection Coon = new SqlConnection(strConn);
if (Coon.State.Equals(ConnectionState.Closed))
{
Coon.Open();
}
return Coon;
}
// 执行带参数的存储过程
public static SqlCommand CreateCmd(string procName, SqlParameter[] prams, SqlConnection Conn)
{
SqlConnection SqlConn = Conn;
if (SqlConn.State.Equals(ConnectionState.Closed))
{
SqlConn.Open();
}
SqlCommand Cmd = new SqlCommand();
Cmd.CommandType = CommandType.StoredProcere;
Cmd.Connection = SqlConn;
Cmd.CommandText = procName;
if (prams != null)
{
foreach (SqlParameter parameter in prams)
{
if (parameter != null)
{
Cmd.Parameters.Add(parameter);
}
}
}
return Cmd;
}
3.使用SqlBulkCopy
下面以导入学生消课数据为例,导入数据的方法,关于SqlBulkCopy(官方解释:允许你使用其他源的数据有效地批量加载 SQL Server 表。)的使用可以到到网上搜索,资料一大堆,官方文档直通通车
首先要构造要导入数据格式的DataTable类型的对象(TransferData)、其次要设置和数据源的列映射关系
Stopwatch 用于计算导入数据耗费时间
private void InsertTwo()
{
OpenFileDialog fd = new OpenFileDialog();
if (fd.ShowDialog() != DialogResult.OK)
{
return;
}
Stopwatch sw = new Stopwatch();
//给datatable 构造Column
DataTable dt = Tools.TransferData(fd.FileName, "sheet1","");
dt.Columns.Add(xhFee);
this.btn_Import.Enabled = false;
string strConn = System.Configuration.ConfigurationManager.AppSettings["SsConnString"];
using (SqlConnection conn = new SqlConnection(strConn))
{
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
bulkCopy.DestinationTableName = "T_FI_IncomeDetail";
bulkCopy.BatchSize = dt.Rows.Count;
//设置列对应关系
bulkCopy.ColumnMappings.Add("辅导类型", "FdId");
bulkCopy.ColumnMappings.Add("消耗课时或课次", "XhKeshi");
bulkCopy.ColumnMappings.Add("消耗日期", "CreateTime");
bulkCopy.ColumnMappings.Add("学生姓名", "Name");
conn.Open();
sw.Start();
int totalRow = dt.Rows.Count;
if (dt != null && dt.Rows.Count != 0)
{
dateTimeDelete.Value = Convert.ToDateTime(dt.Rows[0]["消耗日期"]);
bulkCopy.WriteToServer(dt);
sw.Stop();
}
MessageBox.Show(string.Format("插入{0}条记录共花费{1}毫秒", totalRow, sw.ElapsedMilliseconds));
}
}
// 获取excel数据并填充到DataTable
public static TransferData(string excelFile, string sheetName,string strScreen)
{
System.Data.DataTable dt = new System.Data.DataTable();
try
{
//获取全部数据
string strConn = "Provider=Microsoft.Ace.Oledb.12.0;Data Source=" + excelFile + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=1;'";
OleDbConnection conn = new OleDbConnection(strConn);
conn.Open();
OleDbDataAdapter myCommand = null;
myCommand = new OleDbDataAdapter("Select * from [Sheet1$] " + strScreen, strConn);
myCommand.Fill(dt);
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return dt;
}
4.使用SQLServer表值参数
该方法对于需要批量导入数据,有需要对数据进行逻辑操作,影响多张表时,尤其实用;本例以导入用户资料为例,亲测由于逻辑复杂在存储过程中使用游标处理2000条数据,2s就可完全导入。
主要是应用了SQLServer的表类型参数,通过给存储过程传入表数据,让sql操作都在数据库中进行,提升操作性能。
首先要根据要在数据库 创建自定义表类型,创建语句格式如下:
CREATE TYPE [dbo].[UserInfo] AS TABLE(
[Name] [varchar](32) NULL,
[Code] [varchar](32) NULL,
[Gender] [varchar](32) NULL,
[Birthday] [datetime] NULL
)
存储过程使用方式:UserInfo即为提前创建好的自定义表类型
create proc procName
(
@DataTable UserInfo readonly
)
as
begin
-- 实现自己的逻辑对@DataTable的使用可以向普通表一样,
-- 建议 如果需要对@DataTable需要连表过滤数据,请使用临时表, 否则可能会提示 超出数据库设置的最大查询时间
--(在数据库引擎,右键属性--连接中可以查看使用查询*器防止查询时间过长,不勾选默认30s),
-- 建议逻辑操作能放在代码中处理的,不要放在存储过程中,为了减小数据库服务器压力
end
代码调用实例:
private int DataImport1(object sender)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string path = "d:\数据导入日志.txt";
if (File.Exists(path))
File.Delete(path);
int count = m_dt.Rows.Count;
SqlConnection Conn = SsZongs.ReturnConn();
DataTable dt = new DataTable("userIfo");
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Code", typeof(string));
dt.Columns.Add("Gender", typeof(string));
dt.Columns.Add("Birthday", typeof(DateTime));
try
{
for (int i = 0; i < count; i++)
{
try
{
dt.Rows.Add((m_dt.Rows[i]["姓名"] + "").Trim(),
m_dt.Rows[i]["编号"].ToString(),
m_dt.Rows[i]["性别"].ToString(),
m_dt.Rows[i]["出生日期"]
);
}
catch (Exception)
{
MessageBox.Show("确保数据表中的列名和模版中的一致!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return -1;
}
}
Tools.insertTableToDB(dt, "procName");
}
catch (Exception ex)
{
Tools.Log_Write(ex.Message, "d:\数据导入日志.txt");
}
finally
{
sw.Stop();
if (MessageBox.Show("数据导入完成!耗时"+ sw.ElapsedMilliseconds + "毫秒,打开导入日志!", "提示") == DialogResult.OK)
{
this.buttonImport.Enabled = true;
if (File.Exists(path))
System.Diagnostics.Process.Start(path);
}
}
return -1;
}
public static void insertTableToDB(System.Data.DataTable dt,string procName)
{
SqlConnection sqlCon = SsZongs.ReturnConn();
using (var cmd = new SqlCommand(procName, sqlCon))
{
cmd.CommandType = CommandType.StoredProcere;
var param = new SqlParameter("@DataTable", SqlDbType.Structured) { Value = dt };
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
sqlCon.Close();
}
总结
以上几种方式,我在实际工作中都有使用, 具体业务还需要根据情况选择合适的方案。
文档编写能力不好,有需要的可以随时交流。
我的掘金
SQLServer数据批量导入的几种方式
标签:elfuse数据库服务器blebatchtail图片ide资料
C# 批量添加大量数据的问题 mysql
SQL Server的bcp实用工具和BULK INSERT语句是将行快速添加到SQL Server表的传统方法,但ADO.NET 2.0还为用户提供了另外一种方法,即编写新的SqlBulkCopy对象。关系表的DataReader是最普通的行源。此外,用户还能够通过创建有一个或多个要复制的DataTable的运行时间DataSet来从表格化XML文档中插入行。
用SqlBulkCopy将XML文档批量复制到SQL Server表(此过程称为分解)要比SQLXML 3.0的批量加载功能简单得多。批量加载需要一个带注释的XML架构将元素或属性映射到基表列。SqlBulkCopy有一个ColumnMappings集,它允许用户定义源DataTable与目标基表列之间的关系。
以下是通过DataReader将行插入到已有目标基表的步骤。
(1) 为数据源创建一个Connection和一个Command。可以利用任一个.NET数据提供者连接到数据源并创建DataReader。
(2) 用Command.ExecuteReader方法创建一个DataReader。
(3) 创建一个新SqlBulkCopy对象,该对象以连接字符串和对应的SqlBulkCopyOptions枚举成员作为它的两个参数。
(4) 设置SqlBulkCopy.DestinationTableName属性值。
(5) 如果目标表的架构与源表或查询不同,则将ColumnMapping成员添加到ColumnMapping集。
(6) 设置其他可选SqlBulkCopy属性值,如BatchSize和BulkCopyTimeout。
(7) 如果用户的复制操作涉及大量的记录,或者要在速度慢的网络连接中运行,可对SqlBulkCopy.SqlRowsCopied事件添加一个处理查询来显示记录的复制量或百分比。
(8) 调用SqlBulkCopy.WriteToServer方法完成复制操作。
(9) 执行SqlBulkCopy.Close()方法并关闭Connection(如果没有关闭的话),否则重新用SqlBulkCopy对象完成其他操作。
表2-3描述了SqlBulkCopyOptions枚举的成员。
C# 批量添加大量数据的问题 mysql
SQL Server的bcp实用工具和BULK INSERT语句是将行快速添加到SQL Server表的传统方法,但ADO.NET 2.0还为用户提供了另外一种方法,即编写新的SqlBulkCopy对象。关系表的DataReader是最普通的行源。此外,用户还能够通过创建有一个或多个要复制的DataTable的运行时间DataSet来从表格化XML文档中插入行。
用SqlBulkCopy将XML文档批量复制到SQL Server表(此过程称为分解)要比SQLXML 3.0的批量加载功能简单得多。批量加载需要一个带注释的XML架构将元素或属性映射到基表列。SqlBulkCopy有一个ColumnMappings集,它允许用户定义源DataTable与目标基表列之间的关系。
以下是通过DataReader将行插入到已有目标基表的步骤。
(1) 为数据源创建一个Connection和一个Command。可以利用任一个.NET数据提供者连接到数据源并创建DataReader。
(2) 用Command.ExecuteReader方法创建一个DataReader。
(3) 创建一个新SqlBulkCopy对象,该对象以连接字符串和对应的SqlBulkCopyOptions枚举成员作为它的两个参数。
(4) 设置SqlBulkCopy.DestinationTableName属性值。
(5) 如果目标表的架构与源表或查询不同,则将ColumnMapping成员添加到ColumnMapping集。
(6) 设置其他可选SqlBulkCopy属性值,如BatchSize和BulkCopyTimeout。
(7) 如果用户的复制操作涉及大量的记录,或者要在速度慢的网络连接中运行,可对SqlBulkCopy.SqlRowsCopied事件添加一个处理查询来显示记录的复制量或百分比。
(8) 调用SqlBulkCopy.WriteToServer方法完成复制操作。
(9) 执行SqlBulkCopy.Close()方法并关闭Connection(如果没有关闭的话),否则重新用SqlBulkCopy对象完成其他操作。
表2-3描述了SqlBulkCopyOptions枚举的成员。