C# 实体框架的性能

C# 实体框架的性能,c#,performance,entity-framework,C#,Performance,Entity Framework,我还有一个关于EF性能的问题 有一种方法可以从上下文中获取对象: tDocumentTyp DocumentTypObject = Context.tDocumentTyps.Where(s => s.DocumentTypID == iTypID).FirstOrDefault(); 此方法需要约2979 ms 然后,我编写了一个通过反射获取DBSet的方法,执行方式如下: tDocumentTyp DocumentTypObject = Context.GetEntries<t

我还有一个关于EF性能的问题

有一种方法可以从上下文中获取对象:

tDocumentTyp DocumentTypObject = Context.tDocumentTyps.Where(s => s.DocumentTypID == iTypID).FirstOrDefault();
此方法需要约2979 ms

然后,我编写了一个通过反射获取DBSet的方法,执行方式如下:

tDocumentTyp DocumentTypObject = Context.GetEntries<tDocumentTyp>().Where(s => s.DocumentTypID == iTypID).FirstOrDefault();
tDocumentTyp documentypobject=Context.GetEntries()。其中(s=>s.documentypid==iTypID.FirstOrDefault();
我的方法需要约222毫秒才能执行

所以我现在的问题是,为什么我的方法比原来的方法快得多?还是我的方法有什么问题

为了简化这一点,下面是我通过反射获取DBSet的方法:

public static IEnumerable<T> GetEntries<T>(this AppContext DataContext,
    string PropertyName = null, IEnumerable<string> includes = null) where T : IEntity
{
    Type ContextType = typeof(AppContext);
    PropertyInfo Entity = null;
    if (null == PropertyName)
        Entity = ContextType.GetProperty(typeof(T).Name) 
                    ?? ContextType.GetProperty(typeof(T).Name + "s");
    else
        Entity = ContextType.GetProperty(PropertyName);

    if (null == Entity)
        throw new Exception("Could not find the property. If the property is not equal to the tablesname, you have to parametrize it.");
    DbQuery<T> set = ((DbSet<T>)Entity.GetValue(DataContext, null));
    if (includes != null)
        includes.ForEach(f => set = set.Include(f));
    return set;
}
公共静态IEnumerable GetEntries(此AppContext数据上下文,
字符串PropertyName=null,IEnumerable includes=null),其中T:IEntity
{
Type ContextType=typeof(AppContext);
PropertyInfo实体=null;
if(null==PropertyName)
Entity=ContextType.GetProperty(typeof(T).Name)
??ContextType.GetProperty(typeof(T).Name+“s”);
其他的
Entity=ContextType.GetProperty(PropertyName);
if(null==实体)
抛出新异常(“找不到属性。如果属性不等于TableName,则必须对其进行参数化。”);
dbqueryset=((DbSet)Entity.GetValue(DataContext,null));
如果(包括!=null)
includes.ForEach(f=>set=set.Include(f));
返回集;
}

第二个示例是获取整个表并在内存中应用
Where
。您正在应用扩展方法
System.Linq.Enumerable.Where
,该方法在
IEnumerable
上运行。请注意,这是一个内存实现。在第一个示例中,您使用扩展方法
System.Linq.Queryable.Where
,它在
IQueryable
上运行。这是一种不同的方法,尽管它们共享相同的名称

如果仔细检查,您还会发现,在第一个示例中,方法参数的类型为
Expression
,而在第二个示例中,它只是
Func
。这是一个非常重要的区别:可以处理表达式以生成SQL查询


那么为什么第二个更快呢?如果没有关于数据源的更多信息,这很难回答。但是,正如其他人在评论中指出的那样,如果数据库没有索引,那么选择整个表并在内存中执行过滤器可能比让SQL server应用过滤更快。

EF是一种ORM。它生成并执行SQL语句。生成的查询在哪里?基础表是否有索引?你有没有得到同样的结果?您是如何对代码进行基准测试的?您的方法将查询转换为IEnumerable,IEnumerable应该执行查询。嘿,是的,我得到了相同的结果。我可以通过上下文更改值并保存,现在一切正常。。。没有索引没有索引意味着服务器必须搜索所有行才能找到匹配项。但是,您仍然没有发布生成的SQL查询。如果您不知道执行了什么以及针对什么执行了什么,那么就无法对SQL性能进行故障排除—有多少行?如何连接到数据库?你如何计算代码的时间?例如,您可能反复读取缓存值,认为secod方法速度更快。您是否在测试中重用了相同的上下文?@MatthiasBurger您是否在一个接一个地进行基准测试,第一个作为冷查询运行,而第二个上下文已经初始化?第二个查询速度更快,更不用说10倍了,这是没有意义的。在这两种情况下,服务器都必须扫描所有行。在案例#1中,只返回一行。在第二种情况下,整个表将被发回。也许,如果服务器的硬件非常慢,并且数据集很小,那么在客户机上执行计算会更快。但更有可能的是测试代码是错误的,例如,使用缓存values@PanagiotisKanavos服务器不需要“扫描”所有行以返回整个表,如果存在
where
,则不需要这样做。在大多数服务器实现中,选择整个表是一项优化操作。编辑:我只是想澄清一下,我并不是反对你的观点,即它可能不会更快:)只是指出选择整个表是可以优化的。在这两种情况下,表扫描都是必要的-这就是不使用索引时的情况。但是在第一种情况下,queyr很可能是一个
selecttop1。。。其中…
。只返回一行。在第二种情况下,所有行都将显示。事实上,我敢打赌两个查询的执行计划都会显示第二种情况需要更多的IO。不过OP没有提供查询、执行计划甚至数据大小。10x根本不符合逻辑。实际上,如果实体映射到大型表(而不是表)顶部的一个非常复杂的视图,则可能会发生这种情况,当存在筛选器时,会导致更复杂的执行计划。这都是胡思乱想谢谢odyss jii和@Panagiotis Kanavos,如果我发现了什么,我会稍后检查并更新我的问题。。此项目中未启用日志记录。。