Jer*_*ink 3 .net database sql-server transactions
我正在使用.Net 3.5对SQL Server进行一些性能测试.我正在插入100万条记录.当我将它包装在一个事务(可序列化,RepeatabelRead或ReadUncommited)中时,它在我的系统上运行不到80秒.当我删除它在大约300秒内运行的事务.我希望不使用事务是将行插入数据库的最快方法,因为DBMS不需要考虑潜在的回滚.这里发生了什么?这是典型的SQL Server,SQL Server ADO.Net Provider,ADO.Net一般,DBMSes一般吗?
我有iSeries/DB2数据库的背景知识.在DB2中,您必须启用日记功能才能获得承诺控制和事务,并且日志记录相对昂贵.
我真正想要做的是比较SqlCommand插入与实体框架插入,但我对这些结果感到非常惊讶,我想先找出这里的内容.
在我用来运行测试的代码下面.当我运行以下代码时,大约需要74秒(在AtStart日志和AtEnd日志行之间测量)
using (SqlConnection sqlConnection = new SqlConnection(connectionString))
{
sqlConnection.Open();
SqlCommand deleteCommand = new SqlCommand("DELETE FROM LockTest");
deleteCommand.Connection = sqlConnection;
deleteCommand.ExecuteNonQuery();
using (SqlTransaction transaction = sqlConnection.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
try
{
if (DEBUG) LOG.Debug("AtStart");
SqlCommand insertCommand = new SqlCommand();
insertCommand.Connection = sqlConnection;
insertCommand.Transaction = transaction;
insertCommand.CommandText = "INSERT INTO LockTest (Id, Name, Description, Type) " +
"VALUES (@id, @name, @description, @type)";
SqlParameter idParameter = new SqlParameter("@id", System.Data.SqlDbType.UniqueIdentifier);
insertCommand.Parameters.Add(idParameter);
SqlParameter nameParameter = new SqlParameter("@name", System.Data.SqlDbType.NVarChar, 50);
insertCommand.Parameters.Add(nameParameter);
SqlParameter descriptionParameter = new SqlParameter("@description", System.Data.SqlDbType.NVarChar, Int32.MaxValue);
insertCommand.Parameters.Add(descriptionParameter);
SqlParameter typeParameter = new SqlParameter("@type", System.Data.SqlDbType.NChar, 20);
insertCommand.Parameters.Add(typeParameter);
insertCommand.Prepare();
for (int i= 0; i < 1000000; i++)
{
Guid g = Guid.NewGuid();
string s = g.ToString();
insertCommand.Parameters["@id"].Value = g;
insertCommand.Parameters["@name"].Value = s;
insertCommand.Parameters["@description"].Value = DateTime.UtcNow.Ticks.ToString();
insertCommand.Parameters["@type"].Value = "test";
insertCommand.ExecuteNonQuery();
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
sqlConnection.Close();
}
if (DEBUG) LOG.Debug("AtEnd");
Run Code Online (Sandbox Code Playgroud)
记录刷新.
没有显式事务,每个语句(即INSERT)启动的隐式事务必须提交.在将日志中的数据写入磁盘之前,Commit无法返回,这意味着每个INSERT语句都必须等待日志磁盘写入操作.
显式事务必须仅在发出COMMIT语句时等待,并且到那时每个完整日志页面已经提交,并且最后一个日志页面可能包含几个INSERT,因此写入的成本是分摊的.
更新:
您可以在性能计数器中验证日志刷新时间:http://msdn.microsoft.com/en-us/library/ms189883.aspx: