DateTime.Now 如何影响 SQL Server 中的查询计划缓存?
问题:
将 DateTime.Now
作为参数传递给 proc 是否会阻止 SQL Server 缓存查询计划?如果是这样,那么 Web 应用程序是否会错过巨大的性能提升?
可能的解决方案:
我认为DateTime.Today.AddDays(1)
将是一个可能的解决方案。它将把相同的结束日期传递给 sql 过程(每天)。用户仍然可以获得最新的数据。这一点也请讲一下。
给定示例:
假设我们有一个存储过程。它在网页上向用户报告数据。用户可以设置日期范围。如果用户将今天的日期设置为“结束日期”(其中包括今天的数据),则 Web 应用程序会将 DateTime.Now
传递给 sql 过程。
假设一个用户多次运行一份报告(5/1/2010
到now
)。在网页上,用户看到 5/1/2010
到 5/4/2010
。但 Web 应用程序将 DateTime.Now
传递给 sql 过程作为结束日期。因此,尽管用户正在查询相似的日期范围,但过程中的结束日期始终会有所不同。
假设表中的记录数和用户数都很大。因此,任何性能提升都很重要。因此这个问题的重要性。
示例过程和执行(如果有助于理解):
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
。
Question:
Does passing DateTime.Now
as a parameter to a proc prevent SQL Server from caching the query plan? If so, then is the web app missing out on huge performance gains?
Possible Solution:
I thought DateTime.Today.AddDays(1)
would be a possible solution. It would pass the same end-date to the sql proc (per day). And the user would still get the latest data. Please speak to this as well.
Given Example:
Let's say we have a stored procedure. It reports data back to a user on a webpage. The user can set a date range. If the user sets today's date as the "end date," which includes today's data, the web app passes DateTime.Now
to the sql proc.
Let's say that one user runs a report--5/1/2010
to now
--over and over several times. On the webpage, the user sees 5/1/2010
to 5/4/2010
. But the web app passes DateTime.Now
to the sql proc as the end date. So, the end date in the proc will always be different, although the user is querying a similar date range.
Assume the number of records in the table and number of users are large. So any performance gains matter. Hence the importance of the question.
Example proc and execution (if that helps to understand):
CREATE PROCEDURE GetFooData
@StartDate datetime
@EndDate datetime
AS
SELECT *
FROM Foo
WHERE LogDate >= @StartDate
AND LogDate < @EndDate
Here's a sample execution using DateTime.Now:
EXEC GetFooData '2010-05-01', '2010-05-04 15:41:27' -- passed in DateTime.Now
Here's a sample execution using DateTime.Today.AddDays(1)
EXEC GetFooData '2010-05-01', '2010-05-05' -- passed in DateTime.Today.AddDays(1)
The same data is returned for both procs, since the current time is: 2010-05-04 15:41:27
.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
无论参数值如何,查询计划都将被缓存。参数基本上保证存在一致的、可重用的查询,因为就 SQL Server 而言,它们是类型安全的。
你想要的不是查询计划,而是结果缓存。这会受到你所描述的行为的影响。
由于您似乎只处理一整天,因此您可以尝试传入日期而不是日期时间,以最小化不同的参数值。还可以尝试在应用程序中缓存查询结果,而不是每次都进行数据库往返。
The query plan will be cached regardless of parameter values. Parameters basically guarantee that a consistent, reusable query exists, since they are type-safe as far as SQL server is concerned.
What you want is not query plan, but result caching. And this will be affected by the behavior you describe.
Since you seem to handle whole days only, you can try passing in dates, not datetimes, to minimize different parameter values. Also try caching query results in the application instead of doing a database roundtrip every time.
由于您调用的是存储过程,而不是直接查询,因此唯一发生更改的查询是发送到 SQL 的实际批处理,即
EXEC GetFooData '2010-05-01', '2010-05-05' 与
GetFooData '2010-05-01'、'2010-05-04 15:41:27'
。这是一个微不足道的批次,将生成一个微不足道的计划。虽然从严格的技术角度来看,您确实会损失一些性能,但这几乎是无法衡量的。此响应中解释了发生这种情况的详细信息:动态创建的 SQL 与 SQL Server 中的参数好消息是,通过对 SqlClient 调用代码进行微小的更改,即使是其中提到的微小性能改进,您也会受益。将 SqlCommand 代码更改为显式存储过程调用:
附带说明,在数据库中存储本地化时间并不是一个好主意,因为客户端与服务器位于不同的时区,并且由于夏令时的复杂性换个晚上。更好的解决方案是始终存储 UTC 时间,并简单地将其格式化为应用程序中用户的本地时间。
Because you invoke a stored procedure, not directly a query, then your only query that changes is the actual batch you send to SQL, the
EXEC GetFooData '2010-05-01', '2010-05-05'
vs.GetFooData '2010-05-01', '2010-05-04 15:41:27'
. This is a trivial batch, that will generate a trivial plan. While is true that, from a strict technical point of view, you are loosing some performance, it will be all but unmeasurable. The details why this happes are explained in this response: Dynamically created SQL vs Parameters in SQL ServerThe good news is that by a minor change in your SqlClient invocation code, you'll benefit from even that minor performance improvement mentioned there. Change your SqlCommand code to be an explicit stored procedure invocation:
As a side note, storing localized times in the database is not a very good idea, due to the clients being on different time zones than the server and due to the complications of daylight savings change night. A much better solution is to always store UTC time and simply format it to user's local time in the application.
就您而言,如果第二个参数只是实时向上漂移,那么您可能没问题。
不过,您有可能成为 的受害者参数嗅探,其中第一次执行(生成缓存的执行计划)是用参数调用的,这些参数生成的计划通常不适合通常使用的其他参数(或者数据配置文件发生巨大变化)。后面的调用可能会使用一个有时很糟糕的计划,甚至无法正确完成。
如果你的数据配置文件因不同的参数选择而发生巨大的变化,并且执行计划因某些参数的选择而变得很差,你可以将参数屏蔽到局部变量中——这将有效地防止 SQL Server 2005 中的参数嗅探。还有一个WITH RECOMPILE (无论是在 SP 中还是在 EXEC 中 - 但对于频繁调用的 SP,这不是一个可行的选择)在 SQL Server 2008 中,我几乎总是使用 OPTIMIZE FOR UNKNOWN ,这将避免生成基于参数嗅探的计划。
In your case, you are probably fine if the second parameter is just drifting upward in real time.
However, it is possible to become a victim of parameter sniffing where the first execution (which produces the cached execution plan) is called with parameters which produce a plan which is not typically good for the other parameters normally used (or the data profile changes drastically). The later invocations might use a plan which is sometimes so poor that it won't even complete properly.
If your data profile changes drastically by different choices of parameters, and the execution plan becomes poor for certain choices of parameters, you can mask the parameters into local variables - this will effectively prevent parameter sniffing in SQL Server 2005. There is also the WITH RECOMPILE (either in the SP or in the EXEC - but for heavily called SPs, this is not a viable option) In SQL Server 2008, I would almost always use the OPTIMIZE FOR UNKNOWN which will avoid producing a plan based on parameter sniffing.