【问题标题】:Different performance from SQL Server query from Management Studio vs EF Core 5Management Studio 与 EF Core 5 的 SQL Server 查询性能不同
【发布时间】:2021-08-09 05:14:27
【问题描述】:

我编写了一个简单的 EF Core 查询,它使用一些 where 子句对表进行选择以过滤数据:开始日期和结束日期介于实际日期和包含值的字段 (DescrizioneCommessa) 之间。

        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);

要获取原始 SQL,我只需执行以下语句:

            var sql = facis.ToQueryString();

结果查询是:

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]

我注意到与手写版本相比,执行查询需要很长时间:

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

EF 查询甚至需要一分钟以上的时间来详细说明,而正常的查询是立即的。

我确认问题出在 where 子句的这一部分:

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

如果我将上面的行替换为:

   AND (DescrizioneCommessa LIKE '%COMUNE%') 

问题解决了,性能最优。

为什么是这条线

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

造成这个问题?

【问题讨论】:

  • ef 核心 5 还是 ef6?请不要同时标记。

标签: sql sql-server entity-framework-core ef-core-5.0


【解决方案1】:

这是 EF.Core 中记录的行为,如 SO:Entity framework EF.Functions.Like vs string.Contains

所述

一般来说,LIKE 表达式不适用于查询优化器。在更大的数据集中,这成为一个严重的问题,即使它们在更小的未优化集合中工作得很好。优化很大程度上取决于匹配的模式以及它是否是范围查找。在您的情况下,该模式无法使用索引,EF 只是尝试将其转换为 可能 可索引的表达式,在这种情况下,在足够运行该表达式后,其余的数据库洞察引擎会建议您实施适当的索引。

阅读有关在 git hub 中将 String.Contains() 解析为 SQL 的其他讨论:https://github.com/dotnet/efcore/issues/474

当你明确要使用 SQL LIKE 时,EF Core 添加了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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-31
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多