面试题三连问之:EFCore显式编译查询

写于 2022-09-21日

什么是EF Core显示编译

EF Core对我们查询的表达式的编译使用了缓存,当你查询代码需要重用以前执行的查询时,EF Core将使用哈希查找并从缓存中返回已编译的查询。如果能直接对查询进行编译,并跳过哈希的计算和缓存查找那么效率是否会提高呢?这就是显示编译。

在EF Core中显示编译的方法有两个,如下:

EF.CompileQuery()//同步方法
EF.CompileAsyncQuery()异步方法
这两个方法允许您定义一个已编译的查询,然后通过调用一个委托调用它。

实例

接下来我们举例比较显示编译查询和常规查询的性能,为了避免常规数据库在连接查询时带来的不稳定情况,这里我们用内存来做测试。

添加内存数据库的方法:
//首先添加包EntityFrameworkCore.InMemory

install-package Microsoft.EntityFrameworkCore.InMemory
//如果时web程序需要注册一下

    services.AddDbContext<TestDbContext>(options => {
          options.UseInMemoryDatabase(new Guid().ToString());
     });//Guid是内存表名称

注意:内存表仅供测试用,不能用于项目生产环境。

首先我们建个Team类,加入上EF下文,并在数据库中插入不等的数据用来测试用

 public class Team
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public int age{set; get;}
    }
    //建立上下文,并加入Team表
   public class TestDbContext : DbContext
    {
        public TestDbContext(DbContextOptions<TestDbContext> options) : base(options)
        {
        }
        public DbSet<Team> Teams { get; set; }
        public void FillCategories()//插入内存数据库里
        {
            var Team = new List<Team>();
            for (int i = 0; i < 100000; i++)
            {
                Teams.Add(new Team { Id = i, Name = "张山", age = i + 1 });
            }
            Teams.AddRange(Team);
            SaveChanges(true);
        }
    }

接下来我们建一个类,类中有两个方法,一个是普通查询,一个是显式编译查询。然后我们分别调用一下,看看他们所花时间。

   public class TeamsCompileQueryTest
    {
        public TestDbContext teamContext;
        public TeamsCompileQueryTest(TestDbContext teamContext)
        {
            this.teamContext = teamContext;
        }
        public void CompiledQuery()
        {
            Func<TestDbContext, Team3> compileQuery = EF.CompileQuery((TestDbContext context) =>
                context.Teams.OrderBy(o => o.Id).FirstOrDefault());
            var stopWatch = new Stopwatch();
            teamContext.Database.EnsureDeleted();
            teamContext.Database.EnsureCreated();
            stopWatch.Restart();
            for (var i = 0; i < 100; i++)
            {
                var blog = compileQuery(teamContext);
            }
            stopWatch.Stop();
            Console.WriteLine("显示编译查询:" + stopWatch.Elapsed);
        }
        public void UnCompiledQuery()
        {
            Func<TestDbContext, Team3> unCompileQuery = context =>
            {
                return context.Teams.OrderBy(o => o.Id).FirstOrDefault();
            };
            var stopWatch = new Stopwatch();
            teamContext.Database.EnsureDeleted();
            teamContext.Database.EnsureCreated();
            stopWatch.Start();
            for (var i = 0; i < 100; i++)
            {
                var blog = unCompileQuery(teamContext);
            }
            stopWatch.Stop();
            Console.WriteLine("常规查询:" + stopWatch.Elapsed);
        }
    }

接下来调用一下看看效果

teamsCompileQuery.UnCompiledQuery();//常规查询
teamsCompileQuery.CompiledQuery(); //显示编译查询
image

效果如上展示,开始显示编译查询还是比较牛逼的,到后来差距缩小。

结语
对于显示编译查询开始准备拿实际的SQL Server数据库来做测试,但是经过多次测试效果很不理想,甚至普通查询优于显示编译查询。于是采用网上的解决方案用内存数据库来测试。这个玩意如果数据量不是特别大的话不建议采用(个人观点)。如果面试官问到优化,这个还是可以应付一下面试官。

作者:Bo-H

出处:https://www.cnblogs.com/Bo-H/articles/16714854.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Bo-Hong  阅读(612)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题