百万级数据插入方法效率对比


第1种:insert into效率比较慢,但是insert into select会优于其他的先select后插入的
第2种 表值参数批量插入,这个是针对SQL2008以上版本的,速度更快些
使用事务和SqlBulkCopy批量插入数据 SqlBulkCopy是.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其他数据源的数据有效批量的加载到SQL Server表中的功能。类似与 Microsoft SQL Server 包中名为 bcp 的命令行应用程序。但是使用 SqlBulkCopy 类可以编写托管代码解决方案,性能上优于bcp命令行应用程序,更优于如Insert方式向SQL Server表加载大量数据。SqlBulkCopy可以应用到大批量数据的转移上,而不管数据源是什么。
之前在做winform开发的时候,发现当datagridview数据量比较大的时候,用for循环非常耗时间与性能,通过查阅资料,了解到了SqlBulkCopy这种批量的数据转移工具。
下述代码实现了datagridview的批量数据插入。
如果datagridview的列与数据库中的表结构不能完全对应的话,我们需要先将datagridview数据存放到一个DataTable 中,注意DataTable 中的列需要与即将插入的表的列类型兼容,名称与列顺序完全一样。自增列随便填写一个int类型的值即可,也可不写,如果没给自增列指定值的话,在后续的表映射关系中需要明确指出对应关系。因为我这里是用循环来指定表对应关系的,所以对table的字段有严格的要求,其实也可以与数据库表中的字段名不一样,但这样就需要具体指出表之间的对应关系。
DataTable table = new DataTable();
table.Columns.AddRange(new DataColumn[]{
new DataColumn("flow_id",typeof(int)),
new DataColumn("sheet_no",typeof(string)),
new DataColumn("item_no",typeof(string)),
new DataColumn("unit_no",typeof(string)),
new DataColumn("unit_factor",typeof(string)),
new DataColumn("in_price",typeof(string)),
new DataColumn("order_qnty",typeof(string)),
new DataColumn("sub_amount",typeof(string)),
new DataColumn("real_qty",typeof(string)),
new DataColumn("tax_rate",typeof(string)),
new DataColumn("pay_percent",typeof(string)),
new DataColumn("out_qty",typeof(string))});
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow r = dt.Rows[i];
table.Rows.Add(i, sheet_no, r["item_no"], r["unit_no"], r["unit_factor"], r["in_price"], r["order_qnty"], r["sub_amount"], r["real_qty"], r["tax_rate"], r["pay_percent"], r["out_qty"]);
}

//开始数据保存逻辑
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction(); //开启事务

//在插入数据的同时检查约束,如果发生错误调用sqlbulkTransaction事务
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.CheckConstraints, tran);
bulkCopy.DestinationTableName = "***"; //***代表要插入数据的表名
foreach (DataColumn dc in table.Columns)//传入上述table
{
bulkCopy.ColumnMappings.Add(dc.ColumnName, dc.ColumnName); //将table中的列与数据库表这的列一一对应
}
try
{
bulkCopy.WriteToServer(table);
tran.Commit();
}
catch (Exception ex)
{
tran.Rollback();
}
finally
{
bulkCopy.Close();
conn.Close();
}



百万级数据插入测试
在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))

百万级数据插入方法效率对比
文章图片

一、【CCC级】下面我们使用最简单的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 = https://www.it610.com/article/count; sqlComm.Parameters["@p1"].Value = https://www.it610.com/article/string.Format("User-{0}", count * multiply); sqlComm.Parameters["@p2"].Value = https://www.it610.com/article/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,所以我就手动强行停止了。
【百万级数据插入方法效率对比】
二、【BBB级】下面看一下使用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。

三、【AAAA级】最后再看看使用表值参数的效率,会另你大为惊讶的。

表值参数是SQL Server 2008新特性,简称TVPs。对于表值参数不熟悉的朋友,可以参考最新的book online,我也会另外写一篇关于表值参数的博客,不过此次不对表值参数的概念做过多的介绍。言归正传,看代码:
百万级数据插入方法效率对比
文章图片

[c-sharp] view plain copy 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秒。

原文链接:https://www.cnblogs.com/888888CN/p/7157960.html

    推荐阅读