为什么 exec sp_executesql 比 inline sql 慢很多?

Why is exec sp_executesql much slower than inline sql?

我已经在 Management Studio 中测试了这个查询,这个查询执行得非常快(不到一秒)

declare @p_Message_0 varchar(3) = 'whh'
declare @p_CreatedTime_0 datetime = '2015-06-01'

SELECT count(1) FROM (SELECT * FROM [Logs](nolock) WHERE CONTAINS([Message], @p_Message_0) AND [CreatedTime]<@p_CreatedTime_0) t
SELECT t2.* FROM (SELECT t.*,ROW_NUMBER() OVER (ORDER BY Id DESC) as rownum FROM (SELECT * FROM [Logs](nolock) t WHERE CONTAINS([Message], @p_Message_0) AND [CreatedTime]<@p_CreatedTime_0) t) t2 WHERE rownum>0 AND rownum<=20

这样的执行计划:

然后我将它移动到 C# ado.net,它 运行 就像这样

exec sp_executesql N'SELECT count(1) FROM (SELECT * FROM [Logs](nolock) WHERE CONTAINS([Message], @p_Message_0) AND [CreatedTime]<@p_CreatedTime_0) t
SELECT t2.* FROM (SELECT t.*,ROW_NUMBER() OVER (ORDER BY Id desc) as rownum FROM (SELECT * FROM [Logs](nolock) t WHERE CONTAINS([Message], @p_Message_0) AND [CreatedTime]<@p_CreatedTime_0) t) t2 WHERE rownum>0 AND rownum<=20',N'@p_Message_0 varchar(3),@p_CreatedTime_0 datetime',@p_Message_0='whh',@p_CreatedTime_0='2015-06-01'

这个 运行 真的很慢(大约 30 秒)。执行计划如:

我不知道这两个计划有什么不同。 Sql 服务器是带有 SP2 的 2008 R2,我试过参数提示和选项(重新编译),都不适合我。

尝试更新统计信息。第一个使用带有今天日期的变量。变量不会被嗅探,所以你会得到一个猜测的分布。第二个使用参数。这个可以嗅探。

如果统计数据今天没有更新SQL 服务器会认为该日期不存在任何行,因此会在此基础上给出计划。比如估计执行一次TVF但实际执行多次的嵌套循环计划。

又名 the ascending date problem