.NET批量大数据插入性能分析及比较(3.使用事务)
2015-05-06 23:17
429 查看
[c-sharp] view
plaincopy
#region 拼接sql语句并使用Transaction
public static bool ExecuteTransactionInsert(DataTable dt, int batchSize)
{
int count = dt.Rows.Count;
StringBuilder sql = new StringBuilder(220);
bool flag = false;
SqlConnection cn = null;
SqlCommand cmd = null;
try
{
cn = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = cn;
cn.Open();
for (int i = 0; i < count; i += batchSize)
{
sql.Append("begin try;begin tran;");
for (int j = i; j < i + batchSize && j < count; j++)
{
sql.AppendFormat("Insert into TestTable(Id, Name) Values({0}, '{1}');", dt.Rows[j]["Id"], dt.Rows[j]["Name"]);
}
sql.Append("commit tran;end try/nbegin catch/nrollback tran/n end catch");
//LogHelper.Info(sql.ToString());
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
sql.Clear();
}
flag = true;
}
catch (Exception ex)
{
LogHelper.Error(sql.ToString(), ex);
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 Batch Transaction Insert;RecordCount:40000;BatchSize:10;Time:24979;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:20;Time:7669;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:50;Time:5512;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:100;Time:5018;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:200;Time:4557;
[c-sharp] view
plaincopy
#region 拼接sql语句并使用SqlTransaction
public static bool ExecuteSqlTransactionInsert(DataTable dt, int batchSize)
{
int count = dt.Rows.Count;
StringBuilder sql = new StringBuilder(220);
bool flag = false;
SqlConnection cn = null;
SqlCommand cmd = null;
SqlTransaction tran = null;
try
{
cn = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = cn;
cn.Open();
for (int i = 0; i < count; i += batchSize)
{
tran = cn.BeginTransaction();
cmd.Transaction = tran;
for (int j = i; j < i + batchSize && j < count; j++)
{
sql.AppendFormat("Insert into TestTable(Id, Name) Values({0}, '{1}');", dt.Rows[j]["Id"], dt.Rows[j]["Name"]);
}
//LogHelper.Info(sql.ToString());
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
tran.Commit();
sql.Clear();
}
flag = true;
}
catch (Exception ex)
{
try
{
tran.Rollback();
}
catch (Exception tex)
{
LogHelper.Error(sql.ToString(), tex);
}
LogHelper.Error(sql.ToString(), ex);
return false;
}
finally
{
if (tran != null) tran.Dispose();
if (cn != null)
{
if (cn.State == ConnectionState.Open)
{
cn.Close();
}
cn.Dispose();
}
if (cmd != null) cmd.Dispose();
}
return flag;
}
#endregion
结果如下:
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:10;Time:8647;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:20;Time:6255;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:50;Time:5093;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:100;Time:4529;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:200;Time:4469;
没有测试更多的条数,但可以看出来使用事务以后插入速度还是明显提高了(忽略拼接sql语句的耗时),为什么?
我们知道,就SQL Server而言,使用mdf文件保存表、索引等内容,ndf文件忽略,ldf文件保存数据库日志,存储了数据文件的变更信息。
在默认情况下,SQL Server每条插入语句都是一个事务,在这个插入操作中,SQL Server会先修改内存中的数据页标志其为已修改,然后是写数据库日志文件,后台会有单独的线程周期性地检查并将修改写入到mdf文件中。
写日志文件的操作总是顺序的,而写数据文件则通常是随机的,每次插入一条数据,硬盘的磁头都会频繁移动,而且写日志的操作和延迟的写线程同时进行时,此问题就更严重了,如果能将数据文件和日志文件存放在不同的磁盘上,性能应该会有更好的提升。
使用事务后,在一个事务中,将多次对日志文件的修改变成一次修改,所以性能反而得到了提升。
但虽然事务可以改善硬盘的吞吐量,但它也会阻塞其他线程,所以需要进行测试已找到合适的平衡点。
另两种事务的使用方式中使用ADO.NET的SqlTransaction类显然更为让开发人员接受,除非你是打算在拼接sql语句中加入一些特殊的操作。
plaincopy
#region 拼接sql语句并使用Transaction
public static bool ExecuteTransactionInsert(DataTable dt, int batchSize)
{
int count = dt.Rows.Count;
StringBuilder sql = new StringBuilder(220);
bool flag = false;
SqlConnection cn = null;
SqlCommand cmd = null;
try
{
cn = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = cn;
cn.Open();
for (int i = 0; i < count; i += batchSize)
{
sql.Append("begin try;begin tran;");
for (int j = i; j < i + batchSize && j < count; j++)
{
sql.AppendFormat("Insert into TestTable(Id, Name) Values({0}, '{1}');", dt.Rows[j]["Id"], dt.Rows[j]["Name"]);
}
sql.Append("commit tran;end try/nbegin catch/nrollback tran/n end catch");
//LogHelper.Info(sql.ToString());
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
sql.Clear();
}
flag = true;
}
catch (Exception ex)
{
LogHelper.Error(sql.ToString(), ex);
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 Batch Transaction Insert;RecordCount:40000;BatchSize:10;Time:24979;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:20;Time:7669;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:50;Time:5512;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:100;Time:5018;
Use SqlServer Batch Transaction Insert;RecordCount:40000;BatchSize:200;Time:4557;
[c-sharp] view
plaincopy
#region 拼接sql语句并使用SqlTransaction
public static bool ExecuteSqlTransactionInsert(DataTable dt, int batchSize)
{
int count = dt.Rows.Count;
StringBuilder sql = new StringBuilder(220);
bool flag = false;
SqlConnection cn = null;
SqlCommand cmd = null;
SqlTransaction tran = null;
try
{
cn = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = cn;
cn.Open();
for (int i = 0; i < count; i += batchSize)
{
tran = cn.BeginTransaction();
cmd.Transaction = tran;
for (int j = i; j < i + batchSize && j < count; j++)
{
sql.AppendFormat("Insert into TestTable(Id, Name) Values({0}, '{1}');", dt.Rows[j]["Id"], dt.Rows[j]["Name"]);
}
//LogHelper.Info(sql.ToString());
cmd.CommandText = sql.ToString();
cmd.ExecuteNonQuery();
tran.Commit();
sql.Clear();
}
flag = true;
}
catch (Exception ex)
{
try
{
tran.Rollback();
}
catch (Exception tex)
{
LogHelper.Error(sql.ToString(), tex);
}
LogHelper.Error(sql.ToString(), ex);
return false;
}
finally
{
if (tran != null) tran.Dispose();
if (cn != null)
{
if (cn.State == ConnectionState.Open)
{
cn.Close();
}
cn.Dispose();
}
if (cmd != null) cmd.Dispose();
}
return flag;
}
#endregion
结果如下:
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:10;Time:8647;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:20;Time:6255;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:50;Time:5093;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:100;Time:4529;
Use SqlServer Batch SqlTransaction Insert;RecordCount:40000;BatchSize:200;Time:4469;
没有测试更多的条数,但可以看出来使用事务以后插入速度还是明显提高了(忽略拼接sql语句的耗时),为什么?
我们知道,就SQL Server而言,使用mdf文件保存表、索引等内容,ndf文件忽略,ldf文件保存数据库日志,存储了数据文件的变更信息。
在默认情况下,SQL Server每条插入语句都是一个事务,在这个插入操作中,SQL Server会先修改内存中的数据页标志其为已修改,然后是写数据库日志文件,后台会有单独的线程周期性地检查并将修改写入到mdf文件中。
写日志文件的操作总是顺序的,而写数据文件则通常是随机的,每次插入一条数据,硬盘的磁头都会频繁移动,而且写日志的操作和延迟的写线程同时进行时,此问题就更严重了,如果能将数据文件和日志文件存放在不同的磁盘上,性能应该会有更好的提升。
使用事务后,在一个事务中,将多次对日志文件的修改变成一次修改,所以性能反而得到了提升。
但虽然事务可以改善硬盘的吞吐量,但它也会阻塞其他线程,所以需要进行测试已找到合适的平衡点。
另两种事务的使用方式中使用ADO.NET的SqlTransaction类显然更为让开发人员接受,除非你是打算在拼接sql语句中加入一些特殊的操作。
相关文章推荐
- .NET批量大数据插入性能分析及比较(3.使用事务)
- .NET批量大数据插入性能分析及比较(4.使用DataAdapter批量插入)
- .NET批量大数据插入性能分析及比较(5.使用SqlBulkCopy)
- .NET批量大数据插入性能分析及比较(5.使用SqlBulkCopy)
- .NET批量大数据插入性能分析及比较(5.使用SqlBulkCopy)
- .NET批量大数据插入性能分析及比较(4.使用DataAdapter批量插入)
- .NET批量大数据插入性能分析及比较(6.使用表值参数)
- .NET批量大数据插入性能分析及比较(6.使用表值参数)
- .NET批量大数据插入性能分析及比较
- .NET批量大数据插入性能分析及比较
- .NET批量大数据插入性能分析及比较(2.普通插入与拼接sql批量插入)
- .NET批量大数据插入性能分析及比较(1.准备工作)
- .NET批量大数据插入性能分析及比较(1.准备工作)
- .NET批量大数据插入性能分析及比较(2.普通插入与拼接sql批量插入)
- NET批量大数据插入性能分析及比较
- .NET批量大数据插入性能分析及比较(6.使用表值参数)
- Java使用Arrays、ArrayList、LinkedList、Vector实现插入查询性能分析
- MySQL大量数据插入各种方法性能分析与比较
- MySQL性能分析及explain的使用
- [Linux] 使用iostat分析IO性能