在我们的产品中分析一些查询,我发现使用Entity Framework 6参数会影响这一个查询的性能。关于这一点有很多主题,两者都有不同意见。
在我的测试用例中,这两个查询是相同的,除了我已经将params内联到SQL中。
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
SET STATISTICS TIME ON
exec sp_executesql N'SELECT DISTINCT
[Extent1].[POSTerminalID] AS [POSTerminalID]
FROM [dbo].[POSDataEvents] AS [Extent1]
WHERE ([Extent1].[DataTimeStamp] <= @p__linq__0) AND ([Extent1].[DataTimeStamp] >= @p__linq__1) AND ([Extent1].[DataOwnerID] = @p__linq__2)
',N'@p__linq__0 datetime2(7),@p__linq__1 datetime2(7),@p__linq__2 smallint',@p__linq__0='2017-06-22 16:16:01.3570000',@p__linq__1='2017-04-23 04:00:00',@p__linq__2=1
exec sp_executesql N'SELECT DISTINCT
[Extent1].[POSTerminalID] AS [POSTerminalID]
FROM [dbo].[POSDataEvents] AS [Extent1]
WHERE ([Extent1].[DataTimeStamp] <= ''2017-06-22 16:16:01'') AND ([Extent1].[DataTimeStamp] >= ''2017-04-23 04:00:00'') AND ([Extent1].[DataOwnerID] = 1)'
输出统计数据:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
(289 row(s) affected)
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 11859 ms, elapsed time = 5827 ms.
SQL Server Execution Times:
CPU time = 11859 ms, elapsed time = 5828 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
(289 row(s) affected)
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 6221 ms, elapsed time = 509 ms.
SQL Server Execution Times:
CPU time = 6221 ms, elapsed time = 509 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
生成的查询执行计划也略有不同,但仍然访问相同的表。
这让我想到了我的问题:
为什么用参数表示的相同查询慢了近11倍(~6秒到.5秒)?结果使用相同的索引。
如何在实体框架中强制内联参数?我已经看到另一个用户在几个月后从这篇帖子上询问,但没有回复。我不确定这是否是正确的答案,但我想测试一下。我们不会编写原始SQL内联。它必须来自实体框架。
答案 0 :(得分:1)
问题是Entity Framework生成DateTime2类型的参数,而实际数据库列定义为DateTime。有两种解决方案:
将数据库列更改为DateTime2或告诉实体框架改为使用DateTime(see here)。
答案 1 :(得分:0)
我有一个案例,我可选地包括一个昂贵的文本字段。
所以生成的代码具有类似的内容
WHEN @includeExpensiveField = 1 THEN [o].[ExpensiveField] ELSE NULL
因此在SSMS中,当我手动运行查询时,我将其更改为
WHEN 0 = 1
并且完全优化了该字段。
但是,参数化查询必须在计划中解决它,当我在SSMS>查询存储中找到查询时,我可以看到它总是在扫描并加载昂贵的字段,因为它无法对其进行优化。
注意:我使用了这段代码
选择Txt.query_text_id,Txt.query_sql_text,Pl.plan_id,Qry。* FROM sys.query_store_plan AS Pl内联sys.query_store_query AS Qry
ON Pl.query_id = Qry.query_id INNER JOIN sys.query_store_query_text AS Txt
开启Qry.query_text_id = Txt.query_text_id,其中query_sql_text不喜欢last_execution_time desc的'%expensivefield%'顺序
找到使用的query_id
,然后在SSMS>查询存储>跟踪查询中找到实际执行的查询计划