【问题标题】:How does DateTime.Now affect query plan caching in SQL Server?DateTime.Now 如何影响 SQL Server 中的查询计划缓存?
【发布时间】:2010-05-04 22:42:17
【问题描述】:

问题:

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

可能的解决方案:

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

举个例子:

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

假设一位用户多次运行报告--5/1/2010now--多次。在网页上,用户看到5/1/20105/4/2010。但是 Web 应用程序将 DateTime.Now 作为结束日期传递给 sql 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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      因为您调用的是存储过程,而不是直接调用查询,所以您唯一更改的查询是您发送到 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 时间,并在应用程序中简单地将其格式化为用户的本地时间。

      【讨论】:

      • 感谢@Remus 的回答。我正在处理的真正的 sql 查询很复杂;它涉及多个连接表和where 子句。那么性能提升可能不是微不足道的吗?
      • 可能。运行SET STATISTICS TIME ON 后,您可以在 SSMS 查询窗口中运行查询。这将打印出查询编译时间,这将是您可能保存的时间。还有各种性能计数器可以帮助您做出决定,请参阅blogs.msdn.com/sqlprogrammability/archive/2007/01/19/…。请注意,SQL Server 在自动参数化查询方面做得很好,但没有什么比每次都传入完全相同的文本并使用 @parameters 更好。
      【解决方案3】:

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

      但是,有可能成为parameter sniffing 的受害者,其中第一次执行(生成缓存的执行计划)使用参数调用,该参数生成的计划通常不适用于通常使用的其他参数(或数据配置文件发生巨大变化)。后面的调用可能会使用一个有时很糟糕甚至无法正确完成的计划。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-28
        • 2010-11-14
        • 2011-03-22
        • 2020-04-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多