ADO.NET- 中批量添加数据的几种实现方法比较

摘要:
对于(inti=0;dgv.Rows.Count;值(“”),1W条数据将花费3分钟、42秒、842毫秒intrawCount=dataGridView1。排。计数intquota=行计数/1000;j<'{10}'), '); 0){str.Append(“插入BatchTablevalues”);

在.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

免责声明:文章转载自《ADO.NET- 中批量添加数据的几种实现方法比较》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇docker安装启动esSNMP-配置文件详解下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

URL中#号(井号)的作用

今天又看到了一篇非常好的来自HTTPWatch的文章,不得不推荐给大家。 1. 井号在URL中指定的是页面中的一个位置 井号作为页面定位符出现在URL中,比如:http://www.httpwatch.com/features.htm#print ,此URL表示在页面features.htm中print的位置。浏览器读取这个URL后,会自动将print位置...

C#高级编程笔记(22至25章节)文件注册表权限事务

22安全(using System.Security.Principal;) AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);//当前线程用户 var principal = WindowsPrincipal.Current as WindowsPri...

iTween研究院之学习笔记Move移动篇

         最近项目中需要加入一些模型移动的小动画,学习过程中发现了iTween这个类库。它主要的功能就是处理模型从起始点到结束点之间运动的轨迹。(移动,旋转,音频,路径,摄像机等)它是一个开源的项目并且完全免费,它们的官网在这里 http://itween.pixelplacement.com/index.php 打开网之后点击右上角Get iTw...

参数估计

根据样本推断总体的分布或退而求其次推断分布的数字特征,都称为统计推断,它是统计 学的核心 ,这之前我们就说过,你作样本的分析不是最终目的,我们最终是要得到总体 的。 而统计推断的问题又可以分为两大类,一类是估计问题,另一类是假设检验问题。很多实际问题中,总体 的分布类型已知,但它包含一个或几个未知的参数,总体的参数完全 由所含参数决定,这样就需要对未知参数...

【CCS仿真】如何将CCS仿真时memory中的数据以Hex、Integer、 Long 、Float、 Addressable Unit类型保存到PC

2013-12-04 19:07:05 将在CCS中仿真的数据导入电脑上时,可以选择不同的数据类型,以便分析,具体方法如下: 在CCS菜单中,选择File—>Data—>Save,弹出以下窗口:                         在文件名中输入要保存的文件的名字,在保存类型中可以选择保存的文件类型以及格式。文件类型有dat文件与...

as3.0 如何把变量转成XML子节点方法(elements)

游戏新加了一批特殊建筑物,为了给建筑添加浮动信息,由于建筑物太多,不想一个个添加浮动信息,也为了方便以后修改,我把数据配置到外部XML表里, 节点如下 <build_1083 funName="晶石提炼场(1083)" needRank="29"  gotoUrl=""/><!--晶石提炼场(1083) --><build_1...