Entity Framework 6 - 参数查询比内联参数查询慢 11 倍。为什么?
Entity Framework 6 - Parameter query 11x slower than inline parameters query. Why?
分析我们产品中的一些查询,我发现使用 Entity Framework 6 个参数会影响这一查询的性能。关于这个话题很多,大家意见不一。
在我的测试用例中,这两个查询是相同的,除了我将参数内联 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 秒)?结果使用相同的索引。
如何在 entity Framework 中强制内联参数?几个月前,我看到另一位用户在 post 上询问 SO,但没有任何回应。我不确定这是否是正确的答案,但想测试一下。我们不会写原始的 SQL 内联。它必须来自 Entity Framework.
问题是 Entity Framework 生成 DateTime2 类型的参数,而实际的数据库列定义为 DateTime。有两种解决方案:
要么将数据库列更改为 DateTime2,要么告诉 Entity Framework 使用 DateTime (see here)。
我遇到过 可选 包括昂贵的文本字段的情况。
因此生成的代码类似于
WHEN @includeExpensiveField = 1 THEN [o].[ExpensiveField] ELSE NULL
所以在 SSMS 中,当我 运行 手动查询时,我只是将其更改为
WHEN 0 = 1
它完全优化了那个字段。
然而,参数化查询必须在计划中考虑到它,当我在 SSMS > 查询存储中找到查询时,我可以看到它总是在扫描和加载昂贵的字段,因为它无法优化它。
注意:我使用了这段代码
SELECT Txt.query_text_id, Txt.query_sql_text, Pl.plan_id, Qry.* FROM
sys.query_store_plan AS Pl INNER JOIN sys.query_store_query AS Qry
ON Pl.query_id = Qry.query_id INNER JOIN sys.query_store_query_text AS Txt
ON Qry.query_text_id = Txt.query_text_id where query_sql_text not like '%expensivefield%' order by last_execution_time desc
找到使用的 query_id
然后在 SSMS > Query Store > Tracked Queries
中找到实际执行的查询计划
分析我们产品中的一些查询,我发现使用 Entity Framework 6 个参数会影响这一查询的性能。关于这个话题很多,大家意见不一。
在我的测试用例中,这两个查询是相同的,除了我将参数内联 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 秒)?结果使用相同的索引。
如何在 entity Framework 中强制内联参数?几个月前,我看到另一位用户在 post 上询问 SO,但没有任何回应。我不确定这是否是正确的答案,但想测试一下。我们不会写原始的 SQL 内联。它必须来自 Entity Framework.
问题是 Entity Framework 生成 DateTime2 类型的参数,而实际的数据库列定义为 DateTime。有两种解决方案:
要么将数据库列更改为 DateTime2,要么告诉 Entity Framework 使用 DateTime (see here)。
我遇到过 可选 包括昂贵的文本字段的情况。
因此生成的代码类似于
WHEN @includeExpensiveField = 1 THEN [o].[ExpensiveField] ELSE NULL
所以在 SSMS 中,当我 运行 手动查询时,我只是将其更改为
WHEN 0 = 1
它完全优化了那个字段。
然而,参数化查询必须在计划中考虑到它,当我在 SSMS > 查询存储中找到查询时,我可以看到它总是在扫描和加载昂贵的字段,因为它无法优化它。
注意:我使用了这段代码
SELECT Txt.query_text_id, Txt.query_sql_text, Pl.plan_id, Qry.* FROM sys.query_store_plan AS Pl INNER JOIN sys.query_store_query AS Qry
ON Pl.query_id = Qry.query_id INNER JOIN sys.query_store_query_text AS Txt
ON Qry.query_text_id = Txt.query_text_id where query_sql_text not like '%expensivefield%' order by last_execution_time desc
找到使用的 query_id
然后在 SSMS > Query Store > Tracked Queries