I have a table with 10 bilions of rows. When I query with where clausule and a value is hardcoded ( tabulka = tabulka.Where(x => x.Value.Contains("value")
the sql query is send to sql as batch. It tooks about 5 seconds. When the value is not hardcoded ( tabulka = tabulka.Where(x => x.Value.Contains(value)
), the query is send a RPC and it tooks 15 seconds.
This is real example what EF sends to SQL ( from Profiler ):
exec sp_executesql N'SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Tabulka] AS [Extent1]
WHERE ([Extent1].[Column] LIKE @p__linq__0 ESCAPE N''~'') AND ([Extent1].[Column] LIKE @p__linq__1 ESCAPE N''~'')
) AS [GroupBy1]',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)',@p__linq__0=N'%text1%',@p__linq__1=N'%text2%'
This takes 15 seconds.
When I add OPTION (RECOMPILE) it tooks 5 seconds:
exec sp_executesql N'SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Tabulka] AS [Extent1]
WHERE ([Extent1].[Column] LIKE @p__linq__0 ESCAPE N''~'') AND ([Extent1].[Column] LIKE @p__linq__1 ESCAPE N''~'')
) AS [GroupBy1] OPTION (RECOMPILE)',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000)',@p__linq__0=N'%text1%',@p__linq__1=N'%text2%'
It also takes 5 seconds if I rewrite it to simple query:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Tabulka] AS [Extent1]
WHERE ([Extent1].[Column] LIKE '%text1%' AND [Extent1].[Column] LIKE '%text2%')
) AS [GroupBy1]
Question is how force EF to send it as Batch or do something to take 5 seconds instead of 15.
These queries are only as a demo, the real query can be much more complicated and I dont what to rebuild it not to use IQueryable.
Any help will be appriciated. Here are execution plans for queries
The use of sp_executesql is actually the only way to execute a parameterized dynamic SQL statement in SQL Server. There are two primary “execute” primitives in TDS, “batch” and “RPC”. A batch request just contains a T-SQL string, and can be used whenever there is no need for parameters.
Entity Framework Core provides the DbSet. FromSql() method to execute raw SQL queries for the underlying database and get the results as entity objects. The following example demonstrates executing a raw SQL query to MS SQL Server database. var context = new SchoolContext(); var students = context.
The DbSet. FromSqlRaw method ( DbSet. FromSql prior to Entity Framework Core 3.0) enables you to pass in a SQL command to be executed against the database to return instances of the type represented by the DbSet : public class Book.
I can think of a few ways to get around it but as of EF 6.2 and earlier there is no standard/built in way to change how EF creates the query to add hints/options. The problem you are facing is due to an in-efficient query plan that is being persisted in the statistics and is being re-used when you call it with another value. I would first try to figure why the bad query plan is being created and maybe there is a better way to get around it than manipulate the code. To do this try asking the question (minus the EF part) in a Ms Sql forum and include the queries, schema details, and your execution plans like you did in this post.
Please also check your mapping if your nvarchar/varchar column is set for the correct encoding (ascii/unicode) in your DbContext mappings.
Optional work arounds
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With