DateTime.Now如何影响SQL Server中的查询计划缓存?

时间:2010-05-04 22:42:17

标签: sql-server sql-server-2005 caching sql-execution-plan

问题:

DateTime.Now作为参数传递给proc会阻止SQL Server缓存查询计划吗?如果是这样,那么网络应用程序是否错过了巨大的性能提升?

可能的解决方案:

我认为DateTime.Today.AddDays(1)可能是一种解决方案。它会将相同的结束日期传递给sql proc(每天)。用户仍然可以获得最新数据。请同意这一点。

举例:

假设我们有一个存储过程。它将数据报告给网页上的用户。用户可以设置日期范围。如果用户将今天的日期设置为“结束日期”(包括今天的数据),则Web应用程序会将DateTime.Now传递给sql proc。

假设有一个用户多次运行报告 - 5/1/2010now。在网页上,用户会看到5/1/20105/4/2010。但是,Web应用程序将DateTime.Now作为结束日期传递给sql proc。因此,虽然用户正在查询类似的日期范围,但proc中的结束日期将始终不同。

假设表中的记录数和用户数都很大。所以任何性能提升都很重要因此问题的重要性。

示例proc和执行(如果这有助于理解):

CREATE PROCEDURE GetFooData
    @StartDate datetime
    @EndDate datetime
AS

    SELECT *
    FROM Foo
    WHERE LogDate >= @StartDate
    AND LogDate < @EndDate

这是使用DateTime.Now的示例执行:

EXEC GetFooData '2010-05-01', '2010-05-04 15:41:27' -- passed in DateTime.Now

这是使用DateTime.Today.AddDays(1)

的示例执行
EXEC GetFooData '2010-05-01', '2010-05-05' -- passed in DateTime.Today.AddDays(1)

两个过程都返回相同的数据,因为当前时间是:2010-05-04 15:41:27

3 个答案:

答案 0 :(得分:6)

无论参数值如何,都将缓存查询计划。参数基本上保证存在一致的,可重用的查询,因为就SQL服务器而言它们是类型安全的。

您想要的不是查询计划,而是结果缓存。这将受到您描述的行为的影响。

由于您似乎只处理整天,您可以尝试传递日期,而不是日期时间,以最小化不同的参数值。还尝试在应用程序中缓存查询结果,而不是每次都进行数据库往返。

答案 1 :(得分:1)

因为您调用存储过程而不是直接调用查询,所以您更改的唯一查询是您发送给SQL的实际批处理EXEC GetFooData '2010-05-01', '2010-05-05'GetFooData '2010-05-01', '2010-05-04 15:41:27'。这是一个微不足道的批次,将产生一个简单的计划。诚然,从严格的技术角度来看,你正在失去一些表现,但这几乎是不可测量的。此响应中解释了发生这种情况的详细信息:Dynamically created SQL vs Parameters in SQL Server

好消息是,通过对SqlClient调用代码进行微小更改,即使是那里提到的微小性能改进,您也会受益。将您的SqlCommand代码更改为显式存储过程调用:

SqlCommand cmd = new SqlCommand("GetFooData", connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@StartDate", dateFrom);
cmd.Parameters.AddWithValue("@EndDate", DateTime.Now);

作为旁注,在数据库中存储本地化时间不是一个好主意,因为客户端位于与服务器不同的时区,并且由于夏令时改变夜晚的复杂性。一个更好的解决方案是始终存储UTC时间,并将其格式化为用户在应用程序中的本地时间。

答案 2 :(得分:1)

在你的情况下,如果第二个参数只是实时向上漂移,你可能会很好。

然而,有可能成为parameter sniffing的受害者,其中第一次执行(产生缓存的执行计划)被调用参数,这些参数产生的计划通常不适合通常使用的其他参数(或者数据配置文件发生了巨大变化)。后来的调用可能会使用一个有时很差的计划,甚至无法正常完成。

如果您的数据配置文件因参数的不同选择而急剧变化,并且某些参数选择的执行计划变得很差,您可以将参数屏蔽到本地变量中 - 这将有效地防止SQL Server 2005中的参数嗅探。还有WITH RECOMPILE(在SP或EXEC中 - 但对于大量调用的SP,这不是一个可行的选项)在SQL Server 2008中,我几乎总是使用OPTIMIZE FOR UNKNOWN,这将避免基于参数嗅探生成计划