在.Net中经常会遇到批量添加数据,如将Excel中的数据导入数据库,直接在DataGridView控件中添加数据再保存到数据库等等。

方法一:一条一条循环添加

通常我们的第一反应是采用for或foreach循环一条一条的添加。这样的方法可想而知,效率肯定很低,可以慢到操作人员无法接受的那种。经过测试(局域网),1W条数据将会耗时3分42秒842毫秒

for (int i = ; 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 / ; //商
int remainder = rowCount % ; //余数
StringBuilder str = new StringBuilder();
for (int j = ; j < quotient; j++)
{
str.Append("insert into BatchTable values");
for (int i = ; i < ; i++)
{
str.AppendFormat("('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}'),"
, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value,
dataGridView1[, i].Value , dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value,
dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value);
}
string sql = str.ToString().TrimEnd(',');
SqlHelper.ExcuteNonQuery(CommandType.Text, sql, null);
str.Clear();
}
if (remainder > )
{
str.Append("insert into BatchTable values");
for (int i = ; i < remainder; i++)
{
str.AppendFormat("('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}','{10}'),"
, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value
, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, i].Value,
dataGridView1[, i].Value, dataGridView1[, i].Value, dataGridView1[, 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 = ; //超时之前操作完成所允许的秒数
sqlbulkcopy.BatchSize = dt.Rows.Count; //每一批次中的行数
sqlbulkcopy.DestinationTableName = dt.TableName; //服务器上目标表的名称
for (int i = ; 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

ADO.NET- 中批量添加数据的几种实现方法比较的更多相关文章

  1. .Net中批量添加数据的几种实现方法比较

    在.Net中经常会遇到批量添加数据,如将Excel中的数据导入数据库,直接在DataGridView控件中添加数据再保存到数据库等等. 方法一:一条一条循环添加 通常我们的第一反应是采用for或for ...

  2. (转载)MySQl数据库-批量添加数据的两种方法

    方法一:使用excel表格 方法二:使用insert语句(FileWriter批量写入) 使用excel表格 1.打开数据表,按照表的字段在excel中添加数据.注意:表中字段名必须和excel中的名 ...

  3. SQLSERVER数据库中批量导入数据的几种方法

    第一:使用Select Into 语句 如果企业数据库都是采用SQL Server数据库的话,则可以利用select into语句实现数据的导入. select into语句的作用是把数据从另外一个数 ...

  4. Java模拟数据量过大时批量处理数据的两种实现方法

    方法一: 代码如下: import java.util.ArrayList; import java.util.List; /** * 模拟批量处理数据(一) * 当数据量过大过多导致超时等问题可以将 ...

  5. mybatis 批量添加数据的两种实现方式

    做开发的这几年期间经常遇到类似处理这种形式数据的问题,也遇到很多刚刚入行的新同学,发现他们做处理这块,经验不够,今天特地整理了一下,大家都会遇到的几种情况,代码也都粘贴出来了,拿去不谢,有时间大家还是 ...

  6. mybatis批量添加数据的三种方式

    原文地址:https://www.cnblogs.com/gxyandwmm/p/9565002.html

  7. spring boot之使用通用Mapper批量添加数据

    通用Mapper是一款针对mybatis进行扩展的轻量级组件,使用起来非常方便.当调用其针对mysql进行批量添加数据的方法时,发现报错,仔细研究了一番,发现是在使用通用Mapper上出现了问题.下面 ...

  8. Yii2如何批量添加数据

    批量添加这个操作,在实际开发中经常用得到,今天小编抽空给大家整理些有关yii2批量添加的问题,感兴趣的朋友一起看看吧. 在上篇文章给大家介绍了关于浅析Yii2 gridview实现批量删除教程,当然, ...

  9. EF批量添加数据性能慢的问题的解决方案

    //EF批量添加数据性能慢的问题的解决方案 public ActionResult BatchAdd() { using (var db = new ToneRoad.CEA.DbContext.Db ...

随机推荐

  1. 微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io

    原文:微服务实践(七):从单体式架构迁移到微服务架构 - DockOne.io [编者的话]这是用微服务开发应用系列博客的第七篇也是最后一篇.第一篇中介绍了微服务架构模式,并且讨论了微服架构的优缺点: ...

  2. Altium Designer绘制mark点

    mark注:我之前是按照下面的文章去制作的,由于头一次制作没有经验,不是很成功 文章是正确的 只是我的一些配置出错了: 先看一下我们的板子: 关于错误mark点,主要是周边又一圈亮锡,, 原因大概是敷 ...

  3. 实现indexOf

    1.先判断Array数组是否含有indexOf方法,如果有直接返回结果:如果没有则利用循环比较得到结果. function indexOf(arr, item) { if(Array.prototyp ...

  4. php课程 2-7 php中常量如何定义

    php课程 2-7 php中常量如何定义 一.总结 一句话总结:函数方式定义和普通变量方式定义    define('PI','3.14').键值对,和session一样.    const PI=3 ...

  5. PatentTips - SNMP firewall

    BACKGROUND OF THE INVENTION [0001] The present invention relates to communications and, more particu ...

  6. Your algorithm's runtime complexity must be in the order of O(log n).

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  7. javascript中定义事件的三种方式 分类: C1_HTML/JS/JQUERY 2014-08-07 10:27 634人阅读 评论(0) 收藏

    在javascript中,可以为某个元素指定事件,指定的方式有以下三种: 1.在html中,使用onclick属性 2.在javascript中,使用onclick属性 3.在javascipt中,使 ...

  8. 【codeforces 742A】Arpa’s hard exam and Mehrdad’s naive cheat

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  9. js实现md5加密sha1加密等

    1.base64加密 在页面中引入base64.js文件,调用方法为: <!DOCTYPE HTML> <html> <head> <meta charset ...

  10. 解决IE6下PNG透明的JS插件:DD_belatedPNG.js

    DD_belatedPNG是一款解决IE6下PNG透明的JS插件,支持background-position和background-repeat属性,支持伪类.使用方法: <!--[if lte ...