performance - 如何提高使用多个包含的 EF Core 查询的性能
问题描述
我有这个查询,为简洁起见,我将对其进行简化:
public IQueryable<User> GetByIdAsync(Guid userId)
{
return MyContext
.Users
//Bunch of Includes
//Most of which have a ThenInclude
//Followed by another ThenInclude
.FirstOrDefaultAsync(u => u.Id == userId)
}
当为大约 100 个用户运行时,它需要超过 15 秒(在我的机器上本地运行)。不是很好。
我尝试过使用AsNoTracking()
,以及将其更改为使用如下编译的查询:
private static Func<MyContext, Guid, Task<User>> _getByIdAsync =
EF.CompileAsyncQuery((MyContext context, Guid userId) =>
context
.Users
//Same Includes as above
.Where(u => u.Id == userId)
.FirstOrDefault());
public IQueryable<User> GetByIdAsync(Guid userId)
{
return await _getByIdAsync(userId);
}
还是没有区别。
我已经查看了相关线程的这个答案,它建议使用普通的旧 SQL:
我看过这个答案,其中提到了聚集索引:
我当然不能排除任何一个,Includes
因为客户依赖于所有这些信息。在这个阶段,重新设计也不是一种选择。
问题
- 还有其他可以提高性能的选项吗?
- 我在我的任何子表索引中都看不到任何CLUSTERED或NONCLUSTERED标记。这是否值得研究,如果是的话,我可以指出任何解释我如何使用 EF(或不使用)进行更新的文档吗?
解决方案
你有很多方法,但这一切都取决于。
.FirstOrDefaultAsync(u => u.Id == userId)
这意味着对于 100 个用户,您将访问数据库 100 次,因此总共 15 000 / 100 == 等于每个请求 150 毫秒。in
为了改进它,尝试使用类似的子句一次获得所有 100 个用户.Where(u=> userIds.contains(u.Id))
例子。
private static Func<MyContext, Guid, Task<List<User>>> _getByIdAsync =
EF.CompileAsyncQuery((MyContext context, List<Guid> userIds) =>
context
.Users
//Same Includes as above
.Where(u => userIds.Contains(u.Id))).ToListAsync();
- 我对您的数据结构一无所知,但如果您可以使用联接编写 linq,它可能会更快,因为对于一个请求中的多对多,EF 每次每个依赖项都可以访问数据库。
示例如何使用联接进行查询
var query = (from users in context.Users
join otherTable in context.OtherTable on users.Id equals otherTable.UserId).ToList();
- 如果尝试适应通用目的,但有时只有您知道数据才能做得更好,当我有存储库方法来逐个获取数据时,我曾经遇到过与您类似的问题,但后来我编写了新方法来获取数据使用数组,并且该方法负责连接数据,通过 EF 基本上不可能快速完成。所以我在一个请求中说的都是一对一的加载,然后从数据库中读取并使用另一个查询去获取你需要的多对多。
- 你也可以得到sql查询
您可以使用此示例获取 sql
public IQueryable<User> GetByIdAsync(Guid userId)
{
var = query = MyContext
.Users
//Bunch of Includes
//Most of which have a ThenInclude
//Followed by another ThenInclude
var sql = query.ToSql(); // <--------------------------- sql query
return query.FirstOrDefaultAsync(u => u.Id == userId)
}
并使用 sql 查询来分析并查看它是否使用索引。
最后,我真的很讨厌这种public IQueryable GetByIdAsync(Guid userId)之类的方法,问题是大多数时候你不需要所有这些,但是你开始越来越多地使用它们并变得依赖它们......这就是为什么我会建议使用没有存储库模式的 EF,EF 本身是存储库,仅从数据库中获取您需要的数据。
推荐阅读
- javascript - Node.js Puppeteer 如何等待 page.evaluate() 方法
- c# - ASP.NET 核心 MVC。Stripe.StripeException:'没有这样的费用:'txn_1HewOXGhhS4IDSpp9ifQ6hYq''
- c - 这个代码结果是什么?为什么会这样?
- bash - 如何将 wpa_cli 写入文本文件
- cmake - 在 GitHub Actions 中缓存通过 CMake FetchContent 获取的源代码
- ios - CarPlay 中未显示 MyApp
- if-statement - mit-scheme 中的多个 if 语句
- php - 如何在 Laravel 8.0 中自定义登录文件名?
- pattern-matching - ReasonML 记录模式匹配的正确方法
- xml - 除了使用扩展之外,如何在 XSLT 中处理自定义命名空间?