实体框架 - 如何避免查询重新编译

本文关键字:新编译 编译 查询 框架 何避免 实体 | 更新日期: 2023-09-27 18:31:00

我正在努力优化我们的实体框架代码,目前我遇到了一个不确定如何解决的问题。

我们使用的是 Azure SQL + 代码优先实体框架 6.1.3 + Asp.net Web API v2。端点托管在云中,我正在使用它进行测试。

我有一个 API 操作,用于获取过滤、排序和分页的数据。以下是我处理数据的简化代码:

var entities = DbContext.Services
        .Include(q => q.Consumer.Building.Address.Country)
        .Include(q => q.Consumer.Building.Address.State);
entities = entities.OrderBy(x => x.Consumer.RegisteredAt);
entities = entities.Where(x => x.IsDeleted == false); 
entities = entities.Where(x => userId.HasValue ? x.Owner.Id == userId ? true); //this part comes from deep internals, so I cannot change it quickly
var page = entities = entities.Skip(skip).Take(take).ToList();
var count = entities.Count();
var dtoPage = Mapper.Map<IEnumerable<ServiceDto>>(page);
return Page<ServiceDto>(dtoPage, count);

所以代码没有什么例外 - 不使用IN子句等,只是简单的过滤、排序和分页。

问题:调用此方法的执行时间不稳定。我使用一个简单的脚本来调用 API 端点,该端点使用不同的参数调用此代码:它获得 0..5 页,因此 200 次,一个接一个。对于每次调用(第一次除外),我预计调用时间不到 300 毫秒。 但是:从 1200 次总调用中,36 次调用时间超过 1 秒 - 就像在此期间再次重新编译查询一样。通话的平均时间为 250 毫秒,但有时会飙升至 1000 毫秒,相差 4 倍。

测试的常见行为是:

  1. 第一次查询很慢

  2. 第二个查询更快,但仍然比休息慢

  3. 其余查询非常稳定,除了偶尔出现一些峰值。

除了我之外,没有人使用测试环境,所以这不是负载问题,我可以在任何环境中重现它,即使在快速的本地 PC 上 - i5 + 8gb RAM + SSD。

测试之间的延迟也很小 -

所以我的问题是:这个问题从何而来?

  1. 这真的是重新编译问题吗,如果不是,问题的可能来源是什么?
  2. 是否有关于实体框架 6 的查询缓存失效的文档?
  3. 有没有办法将查询保留在缓存中更长的时间,这样如果我现在和 30 分钟后查询该方法,它就不必重新编译它?

实体框架 - 如何避免查询重新编译

这真的是重新编译问题吗,

我不认为这是一个重新编译的问题。但是,您可以通过在Skip中传递 lambda 并Take调用来减少重新编译。请参阅 4.2 使用生成带有常量的查询的函数

如果不是,问题的可能来源是什么?

AFAIK SqlAzure 是共享环境。这可能是您问题的原因。

是否有关于实体框架 6 的查询缓存失效的文档? 有没有办法将查询保留在缓存中更长的时间,这样如果我现在和 30 分钟后查询该方法,它就不必重新编译它?

只要 AppDomain 实体框架查询将保留在内存中,只要服务器不需要内存,SQL

查询计划就会保留在 SQL Server 内存中。与 lambda 的SkipTake也将在这方面有所帮助。在同一页面上看到:

"In EF6 these methods have a lambda overload that effectively makes the
cached query plan reusable because EF can capture variables passed to
these methods and translate them to SQLparameters. This also helps
keep the cache cleaner since otherwise each query with a different
constant for Skip and Take would get its own query plan cache entry"