Skip to content
Advertisement

Different performance from SQL Server query from Management Studio vs EF Core 5

I wrote a simple EF Core query that makes a select on a table using some where clause to filter data: start date and finish date between the actual date and a field (DescrizioneCommessa) containing a value.

        var query = _ctx.Commessas
            .Where(x => (x.DataInizioCommessa.HasValue && x.DataInizioCommessa <= DateTime.Now) || !x.DataInizioCommessa.HasValue)
            .Where(x => (x.DataFineCommessa.HasValue && x.DataFineCommessa >= DateTime.Now) || !x.DataFineCommessa.HasValue)
            .Where(x => x.DescrizioneCommessa.Contains(pattern))
            .OrderBy(x => x.DescrizioneCommessa);

To get the raw SQL I just execute the statement:

            var sql = facis.ToQueryString();

And the resultant query is:

DECLARE @__pattern_0 nvarchar(50) = N'COMUNE';

SELECT *
FROM [Commessa] AS [c]
WHERE (([c].[DataInizioCommessa] IS NOT NULL AND [c].[DataInizioCommessa] <= GETDATE()) OR [c].[DataInizioCommessa] IS NULL) 
       AND (([c].[DataFineCommessa] IS NOT NULL AND ([c].[DataFineCommessa] >= GETDATE())) OR [c].[DataFineCommessa] IS NULL)
       AND ((@__pattern_0 LIKE N'') OR (CHARINDEX(@__pattern_0, [c].[DescrizioneCommessa]) > 0))
ORDER BY [c].[DescrizioneCommessa]

I notice that it takes very long to perform the query comparing to its hand-written version:

SELECT *
FROM Commessa
WHERE (DescrizioneCommessa LIKE '%COMUNE%') 
      AND (DataInizioCommessa <= GETDATE() OR DataInizioCommessa IS NULL) 
      AND (DataFineCommessa >= GETDATE() OR DataFineCommessa IS NULL);

EF Query takes even more than one minute to elaborate, while the normal one is immediate.

I verified that the problem is this part of where clause:

   AND ((@__pattern_0 LIKE N'') OR (CHARINDEX(@__pattern_0, [c].[DescrizioneCommessa]) > 0))

If I substitute the above line with:

   AND (DescrizioneCommessa LIKE '%COMUNE%') 

the problem is resolved, the performance is optimal.

Why this line

.Where(x => x.DescrizioneCommessa.Contains(pattern))

creates this issue?

Advertisement

Answer

This is documented behaviour in EF.Core as discussed on SO: Entity framework EF.Functions.Like vs string.Contains

As a general proposition, LIKE expressions do NOT work well with query optimisers. In larger datasets this becomes a serious problem, even though they work just fine in much smaller unoptimized sets. The optimisation is heavily dependent on the pattern being matched and if it is a ranged lookup or not. In your case the pattern cannot make use indexes, EF is simply trying to convert it into an expression that might be indexable, in which case after running the expression enough the rest of the database insights engines would advise you to implement an appropriate index.

Read about some other discussions about parsing String.Contains() to SQL in git hub: https://github.com/dotnet/efcore/issues/474

When you explicitly want to use SQL LIKE, EF Core added EF.Functions.Like():

var query = _ctx.Commessas
            .Where(x => (x.DataInizioCommessa.HasValue && x.DataInizioCommessa <= DateTime.Now) || !x.DataInizioCommessa.HasValue)
            .Where(x => (x.DataFineCommessa.HasValue && x.DataFineCommessa >= DateTime.Now) || !x.DataFineCommessa.HasValue)
            .Where(x => EF.Functions.Like(x.DescrizioneCommessa, pattern)
            .OrderBy(x => x.DescrizioneCommessa);
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement