表值参数(Table-valued Parameter)是SQL Server 2008增加的新特性,可以将DataTable做为参数传递给存储过程。
数据库执行脚本如下
CREATE TYPE TestType AS TABLE
(
Id int NOT NULL
,Name nvarchar(20) NOT NULL
)
CREATE PROC InsertData
@rows TestType READONLY
as
begin
set nocount on
insert into TestTable(Id, Name)
select Id, Name from @rows
end
代码如下:
- #region 使用表值参数
- public static bool ExecuteTableTypeInsert(DataTable dt, int batchSize)
- {
- int count = dt.Rows.Count;
- bool flag = false;
- SqlConnection cn = null;
- SqlCommand cmd = null;
- DataTable tempTable = Tools.MakeDataTable();
- DataRow row = null;
- try
- {
- cn = new SqlConnection(connectionString);
- cmd = new SqlCommand();
- cmd.Connection = cn;
- cmd.CommandType = CommandType.StoredProcedure;
- cmd.CommandText = "InsertData";
- cn.Open();
- for (int i = 0; i < count; i += batchSize)
- {
- for (int j = i; j < i + batchSize && j < count; j++)
- {
- row = tempTable.NewRow();
- row["Id"] = dt.Rows[j]["Id"];
- row["Name"] = dt.Rows[j]["Name"];
- tempTable.Rows.Add(row);
- }
- SqlParameter param = cmd.Parameters.AddWithValue("@rows", tempTable);
- param.SqlDbType = SqlDbType.Structured;
- param.TypeName = "TestType";
- cmd.ExecuteNonQuery();
- tempTable.Clear();
- cmd.Parameters.Clear();
- }
- flag = true;
- }
- catch (Exception ex)
- {
- LogHelper.Error(ex.Message);
- return false;
- }
- finally
- {
- if (cn != null)
- {
- if (cn.State == ConnectionState.Open)
- {
- cn.Close();
- }
- cn.Dispose();
- }
- if (cmd != null) cmd.Dispose();
- }
- return flag;
- }
- #endregion
结果如下:
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:10;Time:15312;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:20;Time:7806;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:50;Time:3767;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:100;Time:2217;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:200;Time:1743;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:400;Time:1575;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:500;Time:1566;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:600;Time:1374;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:700;Time:1286;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:800;Time:1463;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:1000;Time:1272;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:2000;Time:1069;
Use SqlServer TableType Insert;RecordCount:40000;BatchSize:4000;Time:1001;
从时间上来看,似乎并不必前面的案例强,但批处理量得增加,写性能在持续提高,而且实际上程序中花费了大量的时间在创建DataTable及填充其数据上面,如果传递给函数的就是一个DataTable集合,相信使用表值参数的表现会更好。
但考虑到需要为插入的表创建类型,创建存储过程,个人认为其通用性不是很好
全文链接:
.NET批量大数据插入性能分析及比较(2.普通插入与拼接sql批量插入)
.NET批量大数据插入性能分析及比较(4.使用DataAdapter批量插入)