use*_*827 4 performance sql-server dynamic-sql execution-plan query-performance
我有一个从 .net 应用程序生成的查询,参数是 linq 参数。我用来调整查询的过程如下。
查询的形式是
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
[Extent1].[GroupId] AS [GroupId],
[Extent1].[Agency] AS [Agency],
[Extent1].[Group] AS [Group],
[Extent1].[Claim] AS [Claim],
[Extent1].[StartDate] AS [StartDate],
[Extent1].[ExpireDate] AS [ExpireDate],
[Extent1].[IsActive] AS [IsActive]
FROM [dbo].[Permissions] AS [Extent1]
WHERE ([Extent1].[GroupId] = @p__linq__0) AND (([Extent1].[ExpireDate] IS NULL)
OR ([Extent1].[ExpireDate] > @p__linq__1)) AND ([Extent1].[IsActive] <> 1)',
N'@p__linq__0 int,@p__linq__1 datetime2(7)',
@p__linq__0=15,@p__linq__1='2017-05-10 00:00:00'
Run Code Online (Sandbox Code Playgroud)这只是一个示例查询。实际查询要大得多,并且包括许多涉及多个视图和表等的连接。
我的问题是:
sp_executesql
并将过滤器值应用于查询时,它会在不到 1 秒的时间内运行。我知道由于这些值是硬编码到查询中的,所以它会更快,但为什么执行时间会有这么大的差异?两者的执行计划也不同:
我是在这台服务器上工作的唯一用户,我在两种情况下都执行相同的参数。我已经申请OPTION(RECOMPILE)
到最后,sp_executesql
与 15 秒相比,它在 1 秒内执行。但是执行计划仍然与硬编码计划不相似。
无论如何OPTION(RECOMPILE)
使查询在一秒钟内快速运行,因为它强制查询每次编译和创建新计划。但我不应该破解代码并更改查询。我会建议OPTION(RECOMPILE)
我的申请团队作为最后的手段。
查询优化器能够对动态查询使用参数嗅探,如实际计划中所示:
<ParameterList>
<ColumnReference Column="@p__linq__5" ParameterDataType="varchar(8000)" ParameterCompiledValue="'MI3300287'" ParameterRuntimeValue="'MI3300287'" />
<ColumnReference Column="@p__linq__4" ParameterDataType="datetime2(7)" ParameterCompiledValue="'2009-06-11 23:59:00.0000000'" ParameterRuntimeValue="'2009-06-11 23:59:00.0000000'" />
<ColumnReference Column="@p__linq__3" ParameterDataType="datetime2(7)" ParameterCompiledValue="'2008-06-11 00:00:00.0000000'" ParameterRuntimeValue="'2008-06-11 00:00:00.0000000'" />
<ColumnReference Column="@p__linq__2" ParameterDataType="varchar(8000)" ParameterCompiledValue="'MI3300287'" ParameterRuntimeValue="'MI3300287'" />
<ColumnReference Column="@p__linq__1" ParameterDataType="int" ParameterCompiledValue="(90495)" ParameterRuntimeValue="(90495)" />
<ColumnReference Column="@p__linq__0" ParameterDataType="int" ParameterCompiledValue="(90495)" ParameterRuntimeValue="(90495)" />
</ParameterList>
Run Code Online (Sandbox Code Playgroud)
这些嗅探到的值会影响选择的查询计划。但是,查询计划仍然需要对输入变量的所有可能值都是安全的。让我们看一下计划之间的一个区别,即IncidentDetailsPage_Header
桌子上的访问权限。在较慢的动态计划中,您将获得扫描和哈希匹配,总共需要大约 2.4 秒:
在使用硬编码值的更快计划中,您会得到一个索引查找,而不是大约需要 0 毫秒:
这是与计划的那部分相对应的 T-SQL:
AND (([Extent1].[agencyori] = @p__linq__5)
OR (([Extent1].[agencyori] IS NULL)
AND (@p__linq__5 IS NULL)))
Run Code Online (Sandbox Code Playgroud)
对这些值进行硬编码会生成仅针对这些参数值的单次使用查询计划。使用您的参数值,该 T-SQL 可以简化为:
([Extent1].[AgencyOri] = 'MI3300287')
Run Code Online (Sandbox Code Playgroud)
这符合索引查找的条件。其他代码不是。尽可能避免厨房水槽查询。
归档时间: |
|
查看次数: |
1042 次 |
最近记录: |