Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 初始化属性:“+childrenloadappeased.TotalSeconds+“seconds”); } 使用(实体=新实体()) { before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父级,从include加载子级:“+parentloadappeased.TotalSeconds+”seconds”); } 使用(实体=新实体()) { entities.Configuration.ProxyCreationEnabled=false; entities.Configuration.AutoDetectChangesEnabled=false; entities.Configuration.LazyLoadingEnabled=false; entities.Configuration.ValidateOnSaveEnabled=false; before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父对象,从include加载子对象:“+parentloadappeased.TotalSeconds+”所有内容都已关闭的秒数”); } } }_C#_Sql Server_Entity Framework_Orm_Ef Code First - Fatal编程技术网

C# 初始化属性:“+childrenloadappeased.TotalSeconds+“seconds”); } 使用(实体=新实体()) { before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父级,从include加载子级:“+parentloadappeased.TotalSeconds+”seconds”); } 使用(实体=新实体()) { entities.Configuration.ProxyCreationEnabled=false; entities.Configuration.AutoDetectChangesEnabled=false; entities.Configuration.LazyLoadingEnabled=false; entities.Configuration.ValidateOnSaveEnabled=false; before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父对象,从include加载子对象:“+parentloadappeased.TotalSeconds+”所有内容都已关闭的秒数”); } } }

C# 初始化属性:“+childrenloadappeased.TotalSeconds+“seconds”); } 使用(实体=新实体()) { before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父级,从include加载子级:“+parentloadappeased.TotalSeconds+”seconds”); } 使用(实体=新实体()) { entities.Configuration.ProxyCreationEnabled=false; entities.Configuration.AutoDetectChangesEnabled=false; entities.Configuration.LazyLoadingEnabled=false; entities.Configuration.ValidateOnSaveEnabled=false; before=DateTime.Now; parents=entities.parents.Include(p=>p.Childs.ToList(); parentloadappeased=DateTime.Now-before; System.Diagnostics.Debug.WriteLine(“从DbSet加载父对象,从include加载子对象:“+parentloadappeased.TotalSeconds+”所有内容都已关闭的秒数”); } } },c#,sql-server,entity-framework,orm,ef-code-first,C#,Sql Server,Entity Framework,Orm,Ef Code First,以下是这些测试的结果: public class Parent { public int ParentId { get; set; } public string Name { get; set; } public virtual List<Child> Childs { get; set; } } public class Child { public int ChildId { get; set; } public int Pare

以下是这些测试的结果:

public class Parent
{
    public int ParentId { get; set; }

    public string Name { get; set; }

    public virtual List<Child> Childs { get; set; }
}

public class Child
{
    public int ChildId { get; set; }

    public int ParentId { get; set; }

    public string Name { get; set; }

    public virtual Parent Parent { get; set; }
}
public class Entities : DbContext
{
    public DbSet<Parent> Parents { get; set; }

    public DbSet<Child> Childs { get; set; }
}
USE [master]
GO

IF EXISTS(SELECT name FROM sys.databases
    WHERE name = 'PerformanceParentChild')
    alter database [PerformanceParentChild] set single_user with rollback immediate
    DROP DATABASE [PerformanceParentChild]
GO

CREATE DATABASE [PerformanceParentChild]
GO
USE [PerformanceParentChild]
GO
BEGIN TRAN T1;
SET NOCOUNT ON

CREATE TABLE [dbo].[Parents]
(
    [ParentId] [int] CONSTRAINT PK_Parents PRIMARY KEY,
    [Name] [nvarchar](200) NULL
)
GO

CREATE TABLE [dbo].[Children]
(
    [ChildId] [int] CONSTRAINT PK_Children PRIMARY KEY,
    [ParentId] [int] NOT NULL,
    [Name] [nvarchar](200) NULL
)
GO

INSERT INTO Parents (ParentId, Name)
VALUES (1, 'Parent')

DECLARE @nbChildren int;
DECLARE @childId int;

SET @nbChildren = 25000;
SET @childId = 0;

WHILE @childId < @nbChildren
BEGIN
   SET @childId = @childId + 1;
   INSERT INTO [dbo].[Children] (ChildId, ParentId, Name)
   VALUES (@childId, 1, 'Child #' + convert(nvarchar(5), @childId))
END

CREATE NONCLUSTERED INDEX [IX_ParentId] ON [dbo].[Children] 
(
    [ParentId] ASC
)
GO

ALTER TABLE [dbo].[Children] ADD CONSTRAINT [FK_Children.Parents_ParentId] FOREIGN KEY([ParentId])
REFERENCES [dbo].[Parents] ([ParentId])
GO

COMMIT TRAN T1;
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add
      name="Entities"
      providerName="System.Data.SqlClient"
      connectionString="Server=localhost;Database=PerformanceParentChild;Trusted_Connection=true;"/>
  </connectionStrings>
</configuration>
class Program
{
    static void Main(string[] args)
    {
        List<Parent> parents;
        List<Child> children;

        Entities entities;
        DateTime before;
        TimeSpan childrenLoadElapsed;
        TimeSpan parentLoadElapsed;

        using (entities = new Entities())
        {
            before = DateTime.Now;
            parents = entities.Parents.ToList();
            parentLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load only the parent from DbSet:" + parentLoadElapsed.TotalSeconds + " seconds");
        }

        using (entities = new Entities())
        {
            before = DateTime.Now;
            children = entities.Childs.ToList();
            childrenLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load only the children from DbSet:" + childrenLoadElapsed.TotalSeconds + " seconds");
        }

        using (entities = new Entities())
        {
            before = DateTime.Now;
            parents = entities.Parents.ToList();
            parentLoadElapsed = DateTime.Now - before;

            before = DateTime.Now;
            children = entities.Childs.ToList();
            childrenLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load the parent from DbSet:" + parentLoadElapsed.TotalSeconds + " seconds" +
                                               ", then load the children from DbSet:" + childrenLoadElapsed.TotalSeconds + " seconds");
        }

        using (entities = new Entities())
        {
            before = DateTime.Now;
            children = entities.Childs.ToList();
            childrenLoadElapsed = DateTime.Now - before;

            before = DateTime.Now;
            parents = entities.Parents.ToList();
            parentLoadElapsed = DateTime.Now - before;


            System.Diagnostics.Debug.WriteLine("Load the children from DbSet:" + childrenLoadElapsed.TotalSeconds + " seconds" +
                                               ", then load the parent from DbSet:" + parentLoadElapsed.TotalSeconds + " seconds");
        }

        using (entities = new Entities())
        {
            before = DateTime.Now;
            parents = entities.Parents.ToList();
            parentLoadElapsed = DateTime.Now - before;

            before = DateTime.Now;
            children = parents[0].Childs;
            childrenLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load the parent from DbSet:" + parentLoadElapsed.TotalSeconds + " seconds" +
                                               ", then load the children from Parent's lazy loaded navigation property:" + childrenLoadElapsed.TotalSeconds + " seconds");
        }

        using (entities = new Entities())
        {
            before = DateTime.Now;
            parents = entities.Parents.Include(p => p.Childs).ToList();
            parentLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load the parent from DbSet and children from include:" + parentLoadElapsed.TotalSeconds + " seconds");

        }

        using (entities = new Entities())
        {
            entities.Configuration.ProxyCreationEnabled = false;
            entities.Configuration.AutoDetectChangesEnabled = false;
            entities.Configuration.LazyLoadingEnabled = false;
            entities.Configuration.ValidateOnSaveEnabled = false;

            before = DateTime.Now;
            parents = entities.Parents.Include(p => p.Childs).ToList();
            parentLoadElapsed = DateTime.Now - before;
            System.Diagnostics.Debug.WriteLine("Load the parent from DbSet and children from include:" + parentLoadElapsed.TotalSeconds + " seconds with everything turned off");

        }

    }
}
仅从DbSet加载父级:0972秒

仅从DbSet加载子级:0714秒

从DbSet加载父级:0001秒,然后从DbSet加载子级:86026秒

从DbSet:06864秒加载子级,然后从DbSet:75816159秒加载父级

从DbSet:0秒加载父级,然后从父级的延迟加载导航属性85644549秒加载子级

从DbSet加载父级,从include加载子级:86428788秒

从DbSet加载父级,从include加载子级:91416586秒,所有内容均已关闭

分析


无论何时父对象和子对象处于同一DbContext中,都需要很长时间(9秒)连接所有内容。我甚至尝试过关闭从代理创建到延迟加载的所有功能,但都没有效果。有人能帮我吗?

这不是答案,因为我没有提高性能的解决方案,但是注释部分没有足够的空间用于以下内容。我只想添加一些额外的测试和观察奥斯

首先,我可以几乎准确地复制你在所有七个测试中测得的时间。我在测试中使用了EF4.1

需要注意的一些有趣的事情:

  • 从(快速)测试2中,我可以得出结论,对象物化(将从数据库服务器返回的行和列转换为对象)并不慢

  • 这也通过加载测试3中的实体而不进行更改跟踪来确认:

    parents = entities.Parents.AsNoTracking().ToList();
    // ...
    children = entities.Childs.AsNoTracking().ToList();
    
    虽然也必须具体化250001个对象(但不会建立导航属性之间的关系),但该代码运行速度很快

  • 同样从(快速)测试2中,我可以得出结论,为变更跟踪创建实体快照并不慢

  • 在测试3和4中,当从数据库加载实体时,父级和25000个子级之间的关系得到修复,即EF将所有
    子级
    实体添加到父级的
    子级
    集合中,并将每个子级中的
    父级
    设置为加载的父级。显然,这一步很慢,正如您所说的那样猜测:

    我认为问题在于导航属性的连接 在父母和孩子之间

    尤其是关系的收集端似乎是个问题:如果在
    父类中注释掉
    Childs
    导航属性(那么关系仍然是必需的一对多关系)测试3和4速度很快,尽管EF仍然为所有25000个
    实体设置
    父属性

    我不知道为什么在关系修复期间填充导航集合如此缓慢。如果您以一种天真的方式手动模拟它,就像这样

    entities.Configuration.ProxyCreationEnabled = false;
    
    children = entities.Childs.AsNoTracking().ToList();
    parents = entities.Parents.AsNoTracking().ToList();
    
    parents[0].Childs = new List<Child>();
    foreach (var c in children)
    {
        if (c.ParentId == parents[0].ParentId)
        {
            c.Parent = parents[0];
            parents[0].Childs.Add(c);
        }
    }
    
    这要慢得多(大约4秒)

无论如何,关系修复似乎是性能的瓶颈。如果您需要更改跟踪和更正所连接实体之间的关系,我不知道如何改进它。

我以前回答过。我以前的回答包含了回答此问题的理论,但有了您的详细问题,我可以直接指出问题所在。首先ts使用performance profiler运行一个有问题的案例。这是使用跟踪模式时DotTrace导致的:

修复关系在循环中运行。这意味着对于25000条记录,您有25000次迭代,但每次迭代都会在
EntityCollection
上内部调用
CheckIfNavigationPropertyContainentity

internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
{
    if (base.TargetAccessor.HasProperty)
    {
        object navigationPropertyValue = base.WrappedOwner.GetNavigationPropertyValue(this);
        if (navigationPropertyValue != null)
        {
            if (!(navigationPropertyValue is IEnumerable))
            {
                throw new EntityException(Strings.ObjectStateEntry_UnableToEnumerateCollection(base.TargetAccessor.PropertyName, base.WrappedOwner.Entity.GetType().FullName));
            }
            foreach (object obj3 in navigationPropertyValue as IEnumerable)
            {
                if (object.Equals(obj3, wrapper.Entity))
                {
                    return true;
                }
            }
        }
    }
    return false;
}
随着项目添加到导航属性,内部循环的迭代次数会增加。数学在我的上一个答案中-这是一个算术系列,其中内部循环的总迭代次数为1/2*(n^2-n)=>n^2复杂性。在您的情况下,外部循环中的内部循环会导致312.487.500次迭代,正如性能跟踪所示


我为这个问题创建了。

+1:问题和分析很棒!谢谢你帮我一把!我会编辑你的评论和额外的分析。我也会像你一样设置我的分析格式,它更清楚地显示了用什么测试来推断一个点。我还在等待帮助的时候做了另一个测试。我创建了一个NHibernate使用与此相同POCO和测试代码的数据访问层(最后2个除外),并且每个测试在1秒标记下运行。@CurlyFire:NHibernate是否自动修复关系?例如,在测试3中,NH是否为所有加载的实体将
Child.Parent
Parent.Childs
设置为正确的对象?是的,看起来确实如此。在加载子对象后,我又添加了两行代码(获取父项[0]的计数。子项
internal override bool CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
{
    if (base.TargetAccessor.HasProperty)
    {
        object navigationPropertyValue = base.WrappedOwner.GetNavigationPropertyValue(this);
        if (navigationPropertyValue != null)
        {
            if (!(navigationPropertyValue is IEnumerable))
            {
                throw new EntityException(Strings.ObjectStateEntry_UnableToEnumerateCollection(base.TargetAccessor.PropertyName, base.WrappedOwner.Entity.GetType().FullName));
            }
            foreach (object obj3 in navigationPropertyValue as IEnumerable)
            {
                if (object.Equals(obj3, wrapper.Entity))
                {
                    return true;
                }
            }
        }
    }
    return false;
}