I've got this query, which I'll simplify for brevity:
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)
}
When run for around 100 users, it takes over 15 seconds (running locally on my machine). Not great.
I've tried using AsNoTracking()
, as well as changing it to use a compiled query like so:
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);
}
Still no difference.
I've had a look at this answer for a relevant thread, which suggests using plain old SQL:
https://mcmap.net/q/2032682/-how-to-improve-ef-query-performance-with-20-includes
And I've had a look at this answer, which mentions clustered indexes:
https://mcmap.net/q/2032683/-improving-performance-of-big-ef-multi-level-include
I certainly can't exclude any of the Includes
as the client depends on all this info. Redesigning is also not an option at this stage.
Questions
- Are there any other options that can improve performance?
- I can't see any CLUSTERED or NONCLUSTERED tags in any of my child table indexes. Is this worth looking into and if so, can I be pointed to any documentation that explains how I can go about updating using EF (or without)?
MyContext
created more than once in a given request? A "cold" DbContext tends to take longer to return results than one that's already connected and has a cache. – ImpetusUser
are collections. Viewing the console output, it does appear as though there are multipleSELECT
statements being executed. – Handpick