实体框架性能问题

2024-01-14

我在实体框架方面遇到了一个有趣的性能问题。我正在使用代码优先。

这是我的实体的结构:

一本书可以有很多评论。 评论与一本书相关联。 一篇评论可以有一个或多个评论。 一条评论与一条评论相关联。

public class Book
{
    public int BookId { get; set; }
    // ...
    public ICollection<Review> Reviews { get; set; }
}

public class Review 
{
    public int ReviewId { get; set; }
    public int BookId { get; set; }
    public Book Book { get; set; }
    public ICollection<Comment> Comments { get; set; }
}

public class Comment
{
     public int CommentId { get; set; }
     public int ReviewId { get; set; }
     public Review Review { get; set; }
}

我用大量数据填充了数据库并添加了适当的索引。我正在尝试使用以下查询检索一本有 10,000 条评论的书:

var bookAndReviews = db.Books.Where(b => b.BookId == id)
                       .Include(b => b.Reviews)
                       .FirstOrDefault();

这本书有 10,000 条评论。该查询的性能约为 4 秒。运行完全相同的查询(通过 SQL Profiler)实际上会立即返回。我使用相同的查询、SqlDataAdapter 和自定义对象来检索数据,整个过程在 500 毫秒内完成。

使用 ANTS Performance Profiler,看起来大部分时间都花在做一些不同的事情上:

Equals 方法被调用了 5000 万次。

有谁知道为什么需要调用它 5000 万次以及我如何提高性能?


为什么 Equals 被调用了 50M 次?

听起来很可疑。您有 10,000 条评论和 50,000,000 通电话Equals。假设这是由 EF 内部实现的恒等映射引起的。身份映射确保具有唯一键的每个实体仅被上下文跟踪一次,因此如果上下文已经具有与从数据库加载的记录具有相同键的实例,则它将不会具体化新实例,而是使用现有实例。现在这怎么能与这些数字相符呢?我的可怕猜测是:

=============================================
1st      record read   |  0     comparisons
2nd      record read   |  1     comparison
3rd      record read   |  2     comparisons
...
10.000th record read   |  9.999 comparisons

这意味着每个新记录都会与身份映射中的每个现有记录进行比较。通过应用数学来计算所有比较的总和,我们可以使用称为“算术序列”的东西:

a(n) = a(n-1) + 1
Sum(n) = (n / 2) * (a(1) + a(n))
Sum(10.000) = 5.000 * (0 + 9.999) => 5.000 * 10.000 = 50.000.000

我希望我的假设或计算没有错误。等待!我希望我做错了,因为这看起来不太好。

尝试关闭更改跟踪 = 希望关闭身份映射检查。

这可能很棘手。从...开始:

var bookAndReviews = db.Books.Where(b => b.BookId == id)
                             .Include(b => b.Reviews)
                             .AsNoTracking()
                             .FirstOrDefault();

但是您的导航属性很有可能不会被填充(因为它是通过更改跟踪处理的)。在这种情况下使用这种方法:

var book = db.Books.Where(b => b.BookId == id).AsNoTracking().FirstOrDefault();
book.Reviews = db.Reviews.Where(r => r.BookId == id).AsNoTracking().ToList();

不管怎样,你能看到传递给 Equals 的对象类型是什么吗?我认为它应该只比较主键,甚至 50M 整数比较也不应该是这样的问题。

顺便说一句,EF 很慢 - 这是众所周知的事实。在具体化实体时,它还在内部使用反射,因此仅仅 10,000 条记录就可能需要“一些时间”。除非您已经这样做了,否则您还可以关闭动态代理创建(db.Configuration.ProxyCreationEnabled).

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实体框架性能问题 的相关文章

  • 为什么 C 程序使用 Scanf 给出奇怪的输出?

    我目前正在学习 C 编程 并且遇到了这个奇怪的输出 Program will try functionalities of the scanf function include
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • 链接 .Net 程序集

    这都是假设 所以请耐心等待 假设我正在用 C 编写一个名为 Foo 的工具 输出是 foo exe 我发现了一些我喜欢使用的非常棒的库 称为 Bar 我可以在我的项目中将其引用为 bar dll 当我构建项目时 我的输出目录中有 foo e
  • 如何向 Mono.ZeroConf 注册服务?

    我正在尝试测试 ZeroConf 示例http www mono project com Mono Zeroconf http www mono project com Mono Zeroconf 我正在运行 OpenSuse 11 和 M
  • Makefile 和 .Mak 文件 + CodeBlocks 和 VStudio

    我对整个 makefile 概念有点陌生 所以我对此有一些疑问 我正在 Linux 中使用 CodeBlocks 创建一个项目 我使用一个名为 cbp2mak 的工具从 CodeBlocks 项目创建一个 make 文件 如果有人知道更好的
  • JavaScript 错误:MVC2 视图中的条件编译已关闭

    我试图在 MVC2 视图页面中单击时调用 JavaScript 函数 a href Select a JavaScript 函数 function SelectBenefit id code alert id alert code 这里 b
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • 保证复制省略是否适用于函数参数?

    如果我理解正确的话 从 C 17 开始 这段代码现在要求不进行任何复制 Foo myfunc void return Foo auto foo myfunc no copy 函数参数也是如此吗 下面的代码中的副本会被优化掉吗 Foo myf
  • 在 azure blob 存储中就地创建 zip 文件

    我将文件存储在 Blob 存储帐户内的一个容器中 我需要在第二个容器中创建一个 zip 文件 其中包含第一个容器中的文件 我有一个使用辅助角色和 DotNetZip 工作的解决方案 但由于 zip 文件的大小最终可能达到 1GB 我担心在进
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 以编程方式创建 Blob 存储容器

    我有一个要求 即在创建公司时 在我的 storageaccount 中创建关联的 blob 存储容器 并将容器名称设置为传入的字符串变量 我已尝试以下操作 public void AddCompanyStorage string subDo
  • 在哪里可以找到 Microsoft.Build.Utilities.v3.5

    如何获取 Microsoft Build Utilities v3 5 我正在使用 StyleCop 4 7 Stylecop dll 中的 StyleCop msbuild 任务似乎依赖于 Microsoft Build Utilitie
  • C++ 指针引用混淆

    struct leaf int data leaf l leaf r struct leaf p void tree findparent int n int found leaf parent 这是 BST 的一段代码 我想问一下 为什么
  • 如何高效计算连续数的数字积?

    我正在尝试计算数字序列中每个数字的数字乘积 例如 21 22 23 98 99 将会 2 4 6 72 81 为了降低复杂性 我只会考虑 连续的数字 http simple wikipedia org wiki Consecutive in
  • 如何获取带有某个属性注释的所有属性?

    我刚刚从 Roslyn 开始 我想找到所有用属性名称 OneToOne 注释的属性 我启动了 SyntaxVisualizer 并能够获取对该节点的引用 但我想知道是否有更简单的方法来实现此目的 这就是我所拥有的 var prop docu
  • Streamwriter 覆盖 txt 文件中的文本

    有没有什么方法可以重新打开流写入器而不创建新的写入对象 因为此时 当调用 WriteOdd 时 streamwriter 正在覆盖在它之前调用的 WriteEven public void WriteEven StreamWriter wr
  • 将键码转换为相关的显示字符

    在 C Windows Forms 项目中 我有一个不提供 KeyPressed 事件的控件 它是一个 COM 控件 ESRI 映射 它仅提供 KeyUp 和 KeyDown 事件 包含关键事件参数 http msdn microsoft
  • 从后面的代码添加外部 css 文件

    我有一个 CSS 文件 例如 SomeStyle css 我是否可以将此样式表文档从其代码隐藏应用到 aspx 页面 您可以将文字控件添加到标头控件中 Page Header Controls Add new System Web UI L
  • ContentDialog Windows 10 Mobile XAML - 全屏 - 填充

    我在项目中放置了一个 ContentDialog 用于 Windows 10 上的登录弹出窗口 当我在移动设备上运行此项目时 ContentDialog 未全屏显示 并且该元素周围有最小的填充 在键盘上可见 例如在焦点元素文本框上 键盘和内
  • 如何在 C# 中获取 CMD/控制台编码

    我需要指定正确的代码页来使用 zip 库打包文件 正如我所见 我需要指定控制台编码 在我的例子中为 866 C Users User gt mode Status for device CON Lines 300 Columns 130 K

随机推荐