加载实体实例需要超过 1 秒

2024-05-06

我在EF中遇到了一件有趣的事情。如果我们使用基础实体获取子实体,则加载实体需要更多时间。我的模型看起来像这样:

public abstract class BaseDocument
{
    public Guid Id { get; set; }
    public string Name { get; set; }
}

public abstract class ComplexDocument : BaseDocument
{
    public string AuthorName { get; set; }
}

public abstract class SimpleDocument : BaseDocument
{
    public int Level { get; set; }
}

public abstract class OfficeDocument : ComplexDocument
{
    public string OfficeName { get; set; }
}

public abstract class ClassDocument : SimpleDocument
{
    public string HeadName { get; set; }
}

public class WordDocument : OfficeDocument
{
    public int PagesCount { get; set; }
}

public class ExcelDocument : OfficeDocument
{
    public int SheetsCount { get; set; }
}

public class TextDocument : ClassDocument
{
    public int LinesCount { get; set; }
}

I am using the TPT approach. Here is the inheritance tree inheritance tree Here is my context class:

public class Context : DbContext
{
    public Context() : base(@"Server=(localdb)\MSSQLLocalDB;Database=EFSIX;Trusted_Connection=True;")
    {
        Database.CreateIfNotExists();
    }
    public DbSet<BaseDocument> BaseDocuments { get; set; }
    public DbSet<ComplexDocument> ComplexDocuments { get; set; }
    public DbSet<SimpleDocument> SimpleDocuments { get; set; }
    public DbSet<OfficeDocument> OfficeDocuments { get; set; }
    public DbSet<ClassDocument> ClassDocuments { get; set; }
    public DbSet<ExcelDocument> ExcelDocuments { get; set; }
    public DbSet<WordDocument> WordDocuments { get; set; }
    public DbSet<TextDocument> TextDocuments { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Entity<BaseDocument>().ToTable("BaseDocuments");
       modelBuilder.Entity<ComplexDocument>().ToTable("ComplexDocuments");
       modelBuilder.Entity<SimpleDocument>().ToTable("SimpleDocuments");
       modelBuilder.Entity<OfficeDocument>().ToTable("OfficeDocuments");
       modelBuilder.Entity<ExcelDocument>().ToTable("ExcelDocuments");
       modelBuilder.Entity<WordDocument>().ToTable("WordDocuments");
       modelBuilder.Entity<ClassDocument>().ToTable("ClassDocuments");
       modelBuilder.Entity<TextDocument>().ToTable("TextDocuments");
    }
    public IQueryable<T> GetEntities<T>() where T : class
    {
        return Set<T>();
    }
}

我正在创建一些数据:

static void CreateTestData()
    {
        using (Context context = new Context())
        {
            for (int i = 0; i < 20; i++)
            {
                ExcelDocument excel = new ExcelDocument()
                {
                    Id = Guid.NewGuid(),
                    AuthorName = $"ExcelAuthor{i}",
                    Name = $"Excel{i}",
                    OfficeName = $"ExcelOffice{i}",
                    SheetsCount = (i + 1) * 10
                };
                context.ExcelDocuments.Add(excel);

                WordDocument word = new WordDocument()
                {
                    Id = Guid.NewGuid(),
                    AuthorName = $"WordAuthor{i}",
                    Name = $"Word{i}",
                    OfficeName = $"WordOffice{i}",
                    PagesCount = (i + 2) * 10
                };
                context.WordDocuments.Add(word);

                TextDocument text = new TextDocument()
                {
                    Id = Guid.NewGuid(),
                    Name = $"Text{i}",
                    LinesCount = (i + 3) * 10,
                    HeadName = $"Head{i}",
                    Level = i + 5
                };
                context.TextDocuments.Add(text);
            }
            context.SaveChanges();
        }
    }

我做了两种方法来获取WordDocument来自数据库。其中之一使用BaseDocument另一个使用WordDocument。两者都返回 20 个实例WordDocument:

 static long ReadBaseDoc()
    {
        using (Context context = new Context())
        {
            var words= context.GetEntities<BaseDocument>().Where(e => e.Name.StartsWith("Word"));
            Stopwatch stopwatch = Stopwatch.StartNew();
            var instacnes = excel.ToList();
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }
    }
    static long ReadWordDoc()
    {
        using (Context context = new Context())
        {
            var words = context.GetEntities<WordDocument>().Where(e => e.Name.StartsWith("Word"));
            Stopwatch stopwatch = Stopwatch.StartNew();
            var instacnes = words.ToList();
            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds;
        }
    }

我分别测试了蛾法,几次,平均法ReadWordDoc需要 25ms 和方法ReadBaseDoc需要 52ms(实例相同)。 现在这不是太大的问题,但是当我们有复杂的继承时,它需要超过 1 秒。我创建了10个类并继承自BaseDocument。之后我执行了ReadBaseDoc and ReadWordDoc方法。ReadWordDoc花了 25 毫秒ReadBaseDoc花了 1023 毫秒。实例都是一样的,为什么ReadBaseDoc需要更多时间?在 EF 中避免此类问题的更好方法是什么?


看一看here https://stackoverflow.com/questions/48441674/extremely-slow-ef-startup-15-minutes。有多种方法可以使 EF 更快,但在那些复杂的场景中,ORM 只会产生比它解决的问题更多的问题。

对于您的情况,一种方法是尝试将继承更改为 TablePerType,也许它会更快一点。

另一种方法是找到缓慢的请求并为它们使用 Dapper - 它会快得多。

最后一种方法是创建一个带有实时缓存的存储库,将完整的数据库加载到内存中并保持最新 - 这应该是应用程序中的单例。如果您有多个应用程序使用同一数据库,则需要连接数据更改触发器。

一般来说,我会说,对于像您这样的缓慢(且相对简单)的查询,请使用 Dapper + AutoMapper。保留 EF 以便您的数据库与类保持同步,但不要依赖它进行查询。

如果你真的想坚持使用 ORM,我认为你需要切换 nHibernate。我自己还没有尝试过,但从我读到的内容来看,它在几乎所有可能的方面都是优越的,包括性能和启动时间。

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

加载实体实例需要超过 1 秒 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 按成员序列化

    我已经实现了template
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐