实体框架合并选项未跟踪不良性能
Posted
技术标签:
【中文标题】实体框架合并选项未跟踪不良性能【英文标题】:Entity Framework mergeoption notracking bad performance 【发布时间】:2012-03-04 19:02:36 【问题描述】:我有一个奇怪的行为,试图执行将 ObjectQuery MergeOption 声明为“NoTracking”的查询,在这种情况下,实体框架不应附加任何实体,也不应创建相关的 ObjectStateEntry 来跟踪实体状态。
问题是,如果我尝试指定不跟踪,则相同的查询需要 10 秒(即 AppendingOnly)和更多的 1 分钟,而不是提高性能。
有人对此有解释吗??
【问题讨论】:
您是如何衡量查询执行的? 基本上在使用 ToList() 执行查询之前和之后获取时间戳 但是您执行查询的次数以及您使用的执行顺序是什么? 我执行了一次查询,但我尝试了多次执行,它显然变得更快,但“notracking”查询仍然比“appendingonly”慢。 “执行顺序”是什么意思? 只比较两者的单次执行。如果您在单个应用程序运行中同时执行两者,请尝试以相反的顺序执行它们。 【参考方案1】:如果您通过设置 NoTracking
合并选项来禁用更改跟踪,您可以节省将对象附加到上下文的性能成本,但另一方面您也会失去身份管理。
这意味着可能会实现更多的对象(许多具有相同的键)。
示例:假设您有一个带有Roles
集合作为导航属性的User
实体。还假设您在数据库中有 100 万用户,并且所有用户都具有相同的 10 个角色,即每个用户都有一个包含 10 个元素的角色集合。如果您运行以下查询...
var users = context.Users.Include("Roles").ToList();
...物化和实例化对象的数量取决于合并选项:
如果您不使用NoTracking
,您将在内存中拥有 1.000.010 个对象,即 100 万用户,但只有 10 个角色,因为身份映射将确保每个键只有 1 个角色被物化并附加到上下文。相同的 10 个角色实例用于所有用户的 Roles
集合。
但是,如果您使用NoTracking
,EF 不会将对象附加到上下文,因此身份管理被禁用,您将在内存中拥有 11.000.000 个对象:100 万个用户和每个用户 10 个角色实例,即 1000 万个角色对象。因此,物化对象的数量是对象附加到上下文时的 10 倍以上。
对象物化用"moderate" performance costs分类:
操作:物化对象 相对成本:中等 频率:查询返回的每个对象一次。 评论: 读取返回的 DbDataReader 对象并创建的过程 对象并设置基于中的值的属性值 DbDataRecord 类的每个实例。 如果对象已经存在 在 ObjectContext 中,查询使用 AppendOnly 或 PreserveChanges 合并选项,这个阶段不影响性能。
换句话说:如果查询使用NoTracking
合并选项,此阶段确实会影响性能,并且禁用更改跟踪的性能优势可能会被禁用的缺点破坏身份管理和多重对象物化。
从 EF Core 5.0 开始,有一个额外的选项 'NoTrackingWithIdentityResolution' 会禁用一般跟踪,但会进行身份解析。
【讨论】:
这仍然适用吗? docs.microsoft.com/en-us/ef/core/querying/tracking 说:没有跟踪查询仍在执行查询中执行身份解析。如果结果集中多次包含相同的实体,则每次出现在结果集中都会返回相同的实体类实例。但是,弱引用用于跟踪已返回的实体。如果具有相同标识的先前结果超出范围,并且垃圾收集运行,您可能会获得一个新的实体实例。有关详细信息,请参阅查询的工作原理。 它刚刚与 EF Core 3.0 再次相关 您的链接文档说明了此更改:“无跟踪查询 [...] 不进行身份解析。因此您甚至可以返回新的实体实例当同一实体多次包含在结果中时。此行为在 EF Core 3.0 之前的版本中有所不同"以上是关于实体框架合并选项未跟踪不良性能的主要内容,如果未能解决你的问题,请参考以下文章