我有一张有 100 亿行的表。当我查询 where clausule 和一个值是硬编码的( tabulka = tabulka.Where(x => x.Value.Contains("value")
sql 查询被发送到 sql 作为批处理。大约需要 5 秒。当值不是硬编码( tabulka = tabulka.Where(x => x.Value.Contains(value)
)时,查询是发送一个 RPC 和花了 15 秒。
这是 EF 发送到 SQL(来自 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%'
这需要 15 秒。
当我添加 OPTION (RECOMPILE) 时需要 5 秒:
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%'
如果我将其重写为简单查询,也需要 5 秒:
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]
问题是如何强制 EF 将其作为 Batch 发送或执行某些操作以花费 5 秒而不是 15 秒。
这些查询只是作为一个演示,真正的查询可能要复杂得多,我不知道重建它不使用 IQueryable。
任何帮助都将得到认可。 Here are execution plans for queries
最佳答案
我可以想出几种方法来解决它,但从 EF 6.2 及更早版本开始,没有标准/内置方式来更改 EF 创建查询以添加提示/选项的方式。您面临的问题是由于效率低下的查询计划一直保留在统计信息中,并且在您使用另一个值调用它时会被重新使用。我会首先尝试弄清楚为什么会创建错误的查询计划,也许有比操纵代码更好的方法来解决它。为此,请尝试在 Ms Sql 论坛中提出问题(减去 EF 部分),并包括查询、架构详细信息和您在本文中所做的执行计划。
如果您的 nvarchar/varchar 列在 DbContext 映射中设置为正确的编码(ascii/unicode),请同时检查您的映射。
可选的解决方法
关于c#-4.0 - 如何强制 Entity Framework 不要查询为 sp_executesql,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15970605/