I have an application which does a lot of calculations based on prices, which takes ~87 seconds at the moment. Based on the timeline, I suspect that I am using my includes in a way that is highly suboptimal for Entity Framework, and that I can make major improvements.
My timeline is like this:
- 0 sec - receive GET request
- 2 sec - send query to SQL Server (query with all necessary incudes, the result of which is >40.000 characters. I added some parts at the bottom of the question)
- 5 sec - receive query result from SQL Server
- 45 some thread is exiting
- 46 some thread is exiting
- 50 some thread is exiting
- 80 closing SQL connection (I think that it takes EF6 ~75 seconds to map the query result back to my C# classes but I am not sure)
- 80 starting calculations
- 87 all calculations are done
The query is designed mostly like this
var result = await db.MyAuthorizedFooExtension()
.Include(x => x.Foofie)
.Include(x => x.Bar.Baz)
.Include(x => x.FooFoo.Select(y => y.BarBar))
.Include(x => x.FooFoo.Select(y => y.BazBaz))
//etc.
.ToListAsync()
The result looks like this:
[UnionAll7].[C9] AS [C55],
...
FROM (SELECT
CASE WHEN ([Join2].[ID1] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1],
[Extent1].[ID] AS [ID],
...
[Join2].[ID1] AS [ID5],
...
CAST(NULL AS varchar(1)) AS [C4],
...
FROM [dbo].[Contract] AS [Extent1]
INNER JOIN [dbo].[Leverancier] AS [Extent2] ON [Extent1].[Leverancier] = [Extent2].[ID]
LEFT OUTER JOIN (SELECT [Extent3].[ID] AS [ID1], [Extent3].[Contract] AS [Contract], [Extent3].[ContractStatusOud] AS [ContractStatusOud], [Extent3].[ContractStatusNieuw] AS [ContractStatusNieuw], [Extent3].[MutatieDatumTijd] AS [MutatieDatumTijd], [Extent3].[Medewerker] AS [Medewerker], [Extent3].[Status] AS [Status1], [Extent3].[LastModifiedDate] AS [LastModifiedDate1], [Extent3].[LastModifiedBy] AS [LastModifiedBy1], [Extent4].[ID] AS [ID2], [Extent4].[Naam] AS [Naam], [Extent4].[WindowsNaam] AS [WindowsNaam], [Extent4].[Rol] AS [Rol], [Extent4].[Unit] AS [Unit], [Extent4].[Status] AS [Status2], [Extent4].[LastModifiedDate] AS [LastModifiedDate2], [Extent4].[LastModifiedBy] AS [LastModifiedBy2]
FROM [dbo].[ContractWijzigingHistorie] AS [Extent3]
INNER JOIN [dbo].[Medewerker] AS [Extent4] ON [Extent3].[Medewerker] = [Extent4].[ID] ) AS [Join2] ON [Extent1].[ID] = [Join2].[Contract]
WHERE ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Contract] AS [Extent5]
WHERE ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[Leverancier] AS [Extent6]
WHERE [Extent6].[ID] = [Extent5].[Leverancier]
)) AND ([Extent5].[ID] = [Extent1].[ID])
)) AND ([Extent1].[Status] IN (1)) AND ((DATEPART (year, [Extent1].[Startdatum])) <= @p__linq__0) AND ((DATEPART (year, [Extent1].[Einddatum])) >= @p__linq__1)
UNION ALL
SELECT
2 AS [C1],
[Extent7].[ID] AS [ID],
...
CAST(NULL AS int) AS [C9],
CAST(NULL AS datetime2) AS [C10],
...
[Extent9].[PeriodeWaarde] AS [PeriodeWaarde],
...
[Project9].[LastModifiedBy] AS [LastModifiedBy],
...
[UnionAll5].[ID2] AS [C60],
...
CAST(NULL AS int) AS [C62],
...
etc.
How do I improve the performance while still using Entity Framework?