9.14、EF Core 高性能

数据库操作是线上系统的核心,对系统的响应快慢也起着根本性的作用。

高性能建议

  • 请以异步方式调用所有数据访问 api。

  • 检索的数据不是必需的。 编写查询以仅返回当前 HTTP 请求所必需的数据。

  • 如果数据可以接受,请考虑缓存经常访问的从数据库或远程服务检索的数据。 使用 MemoryCache 或 microsoft.web.distributedcache ,具体取决于方案。

  • 尽量减少网络往返次数。 目标是使用单个调用而不是多个调用来检索所需数据。

  • 在访问数据时,请不要在 Entity Framework Core 中使用无跟踪查询。 EF Core 可以更有效地返回无跟踪查询的结果。 筛选和聚合 LINQ 查询(例如, .Where使用.Select、或.Sum语句),以便数据库执行筛选。

  • 请考虑 EF Core在客户端上解析一些查询运算符,这可能导致查询执行效率低下。

  • 不要对集合使用投影查询,这可能会导致执行 "N + 1" 个 SQL 查询。

  • 使用 DbContextPool 池来管理 DbContext,类似 ADO.NET 的连接池。

  • 手动或显式编译的查询 API,允许应用程序缓存查询转换,使其可仅被计算一次并执行多次。

// Create an explicitly compiled query
private static Func<CustomerContext, int, Customer> _customerById =
    EF.CompileQuery((CustomerContext db, int id) =>
        db.Customers
            .Include(c => c.Address)
            .Single(c => c.Id == id));

// Use the compiled query by invoking it
using (var db = new CustomerContext())
{
   var customer = _customerById(db, 147);
}

将DbContext分成多个子DbContext

正常情况下,我们的系统只有一个继承 DbContext 的类,也就是我们所有模型、存储过程、视图、函数等都是写在这个类中。随着系统越来越复杂,这个类也就越来越大,这样就会大大影响 DbContext 首次冷加载的时候会加载所有定义的模型、存储过程、视图、函数等。

所以、建议我们把系统划分成多个子模块,每一个子模块有自己独立的 DbContext 类,这样冷加载的性能大大提升,数据库操作也就响应越来越快!

具体怎么实现多个 DbContext 查查阅 9.11、多上下文、读写分离 章节。

启用行版本控制功能

-- 设置为单用户
ALTER DATABASE AlliantDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
GO
-- 开启行版本(事务级)
ALTER DATABASE AlliantDB SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
-- 开启语句级行版本
ALTER DATABASE AlliantDB SET READ_COMMITTED_SNAPSHOT ON WITH no_wait
GO
-- 设置为多用户
ALTER DATABASE AlliantDB SET MULTI_USER WITH ROLLBACK IMMEDIATE;
GO

最后更新于