我一直得到下图中显示的结果。我想知道我是否可以做些什么来提高可预测性。我没有使用SqlBulkCopy,因为我需要利用 EFv5 的验证功能。
如果有人可以验证/反驳我的发现,那就太好了。我的目标是摆脱这两种尖峰。我在下面提供源代码,以便您快速完成。您所需要的只是 VS 中的一个类库项目,其中包含对 EFv5 和 NUnit 的引用,两者都可以通过 NuGet 获得。只需将此代码粘贴到 Class1 中,修改连接字符串,然后运行它。您可以使用下面的 sql 脚本重新创建表。
我正在使用 .Net 4.5、EF 5、NUnit 2.6.1,在发布模式下运行代码,没有附加调试器。数据库是 SqlServer 2008 R2。我在 64 位模式下使用 NUnit.exe 运行测试,其中显示“Net 4.0”作为框架版本。
X 轴是批号(总共 1000 个批次),Y 轴是毫秒。您可以看到第一批大约需要 30 秒,这是预期的,因为 dbContext 是“冷”的。每批保存 100 个实体。
请注意,这个问题正在寻找这个答案中缺少的一些信息,它是 EF 保存中的抖动。
这是我正在使用的代码:
桌子:
CREATE TABLE [dbo].[Entity1](
[Id] [int] IDENTITY(1,1) NOT NULL,
[IntField] [int] NOT NULL,
[StrField] [nvarchar](50) NOT NULL,
[DateField] [datetimeoffset](7) NOT NULL,
CONSTRAINT [PK_Entity1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
课程:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using NUnit.Framework;
namespace ClassLibrary1
{
public class Entity1
{
public int Id { get; protected set; }
public int IntField { get; set; }
public string StrField { get; set; }
public DateTimeOffset DateField { get; set; }
}
public class MyContext : DbContext
{
public MyContext(string connStr) : base(connStr) { }
public virtual DbSet<Entity1> Entities { get { return base.Set<Entity1>(); } }
}
[TestFixture]
public class Class1
{
[Test]
public void EfPerf()
{
var entities = buildEntities(100000);
int batchSize = 100;
var batchTimes = new List<Stopwatch>();
for (int i = 0; i < entities.Length; i += batchSize)
{
var sw = Stopwatch.StartNew();
using (var ctx = buildCtx())
{
for (int j = i; j < i + batchSize; j++)
ctx.Entities.Add(entities[j]);
ctx.SaveChanges();
}
sw.Stop();
batchTimes.Add(sw);
}
batchTimes.ForEach(sw => Console.Out.WriteLine("Elapsed ms: " +
sw.ElapsedMilliseconds));
}
private MyContext buildCtx()
{
var cs = "Data Source=your db server;" +
"Initial Catalog=your db;" +
"Persist Security Info=True;" +
"User ID=your user;" +
"Password=your pwd";
var ctx = new MyContext(cs);
//ctx.Configuration.ProxyCreationEnabled = false;
return ctx;
}
private Entity1[] buildEntities(int count)
{
var entities = new Entity1[count];
for (int i = 0; i < count; i++)
entities[i] = new Entity1 { IntField = i, StrField = "str" + i,
DateField = DateTimeOffset.UtcNow };
return entities;
}
}
}