实体框架6 - 参数查询比内联参数查询慢11倍。为什么呢?

时间:2017-06-22 21:47:23

标签: c# sql-server linq entity-framework-6 linq-to-entities

在我们的产品中分析一些查询,我发现使用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.

生成的查询执行计划也略有不同,但仍然访问相同的表。

enter image description here

这让我想到了我的问题:

  1. 为什么用参数表示的相同查询慢了近11倍(~6秒到.5秒)?结果使用相同的索引。

  2. 如何在实体框架中强制内联参数?我已经看到另一个用户在几个月后从这篇帖子上询问,但没有回复。我不确定这是否是正确的答案,但我想测试一下。我们不会编写原始SQL内联。它必须来自实体框架。

2 个答案:

答案 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>查询存储>跟踪查询中找到实际执行的查询计划