We are using entity framework to work with a table with 50 million entries (at a Microsoft SQL Server).
public async Task<List<TableName>> MyMethod(int fooId, int count)
{
using (var context = new Context(ConnectionString))
{
return
await context.TableName.AsNoTracking()
.Where(_ => _.FooId== fooId)
.OrderByDescending(_ => _.DateCreated)
.Take(count)
.ToListAsync();
}
}
Entity Framework translates this to (beautified):
declare @fooId int = 42
SELECT TOP (100) *
FROM TableName
WHERE FooId = @fooId
ORDER BY DateCreated DESC
The columns FooId and DateCreated both got an index, but SQL Server does a full table scan anyway, which takes very long. This is caused because 42 is assigned outside of the statement (and seems to be related to selectivity). The indexes would be used if you wrote
WHERE FooId = 42
Is there a way to get Entity Framework to optimize the generated query? At the moment, my only way seems to be using raw SQL queries for huge tables in my code :-/ Is there a better workaround?
Edit: More details as requested in the comments: Non beautified query that is generated by entity framework:
SELECT TOP (100)
[Project1].[DateCreated] AS [DateCreated],
[Project1].[FooId] AS [FooId]
FROM ( SELECT
[Extent1].[DateCreated] AS [DateCreated],
[Extent1].[FooId] AS [FooId]
FROM [dbo].[TableName] AS [Extent1]
WHERE [Extent1].[FooId] = @p__linq__0
) AS [Project1]
ORDER BY [Project1].[DateCreated] DESC
-- p__linq__0: '42' (Type = Int32, IsNullable = false)
The create script for the index:
CREATE NONCLUSTERED INDEX [IX_TableName_FooId] ON [dbo].[TableName]
(
[FooId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85) ON [SECONDARY]
GO
Create script for my table:
CREATE TABLE [dbo].[TableName](
[DateCreated] [datetime] NOT NULL,
[FooId] [int] NULL
) ON [PRIMARY]