c# - 为什么 EF5 在 SaveChanges() 时间产生这些尖峰?

标签 c# performance sql-server-2008-r2 entity-framework-5

我一直得到下图中显示的结果。我想知道我是否可以做些什么来提高可预测性。我没有使用 SqlBulkCopy因为我需要利用 EFv5 的验证功能。

如果有人可以验证/反驳我的发现,那就太好了。我的目标是摆脱这两种尖峰。我在下面提供了源代码,以便您快速使用。您只需要一个 VS 中的类库项目,其中包含对 EFv5 和 NUnit 的引用,两者都可通过 NuGet 获得。只需将这段代码粘贴到 Class1 中,修改连接字符串,然后运行即可。您可以使用下面的 sql 脚本重新创建表。

我正在使用 .Net 4.5、EF 5、NUnit 2.6.1,在 Release模式下运行代码,没有附加调试器。数据库是 SqlServer 2008 R2。我在 64 位模式下使用 NUnit.exe 运行测试,它显示“Net 4.0”作为框架版本。

EFv5 simple entity insert. 1000 batches of 100 entities

X 轴是批号(总共 1000 个批处理),Y 轴是毫秒。您可以看到第一批大约需要 30 秒,这是预期的,因为 dbContext 是“冷的”。每批保存 100 个实体。

请注意,此问题正在寻找 this answer 中缺失的一些信息,它是 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;
        }
    }
}

最佳答案

我感觉您遇到了数据库死锁问题。 EF 将所有 saveChanges() 调用放在一个事务中。默认情况下,SQL Server 中的事务以高度限制的已提交读运行。也许您可以尝试这样更改隔离级别:

 using (var scope = new TransactionScope(TransactionScopeOption.Required, new 
 2: TransactionOptions { IsolationLevel= IsolationLevel.Snapshot }))
 3: {
 4: // do something with EF here
 5: scope.Complete();
 6: }

关于c# - 为什么 EF5 在 SaveChanges() 时间产生这些尖峰?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12239794/

相关文章:

c# - 使用正则表达式模式查找列表中是否存在项目

c# - 林克错误 : not contain a definition for 'InsertOnSubmit'

node.js - 如何增加 REDIS CPU 使用率

sql-server-2008-r2 - SQL Server 2008 R2 中的 SQL 切换/案例

javascript - SSRS 报告管理器 JavaScript 在非 IE 浏览器中无法显示下拉菜单

c# - MVC URL.RouteUrl 删除 RouteValues 但 URL.Action 保留它们?

c# - 确定谁调用事件处理程序

Android:低 FPS 在表面 View 中绘制许多位图

javascript - 新浏览器是否以不同方式优化循环?

sql-server - 意外的 sp_MSForEachDB 行为