我不喜欢在 SQL Server 中处理日期,并且永远记不起如何立即执行一些简单的任务。
其中之一是截断今天的日期。
convert(datetime, datediff(day, 0, getdate()))
我想开始为这些创建包装函数以提高可读性和参考性。
create or alter function
/* Returns the date as of today at midnight (truncated)
*
* i.e.
* getdate() -> 2023-12-04 10:26
* date_today_midnight() -> 2023-12-04 00:00
*/
dbo.date_today_midnight()
returns
datetime
as begin
return convert(datetime, datediff(day, 0, getdate()));
end
不幸的是,当我将新函数替换为 where 子句时,性能会受到很大影响。
select * from aTable where aDate >= convert(datetime, datediff(day, 0, getdate()));
-- runtime < 1s
select * from aTable where aDate >= date_today_midnight();
-- runtime > 10s
根据我的理解,问题与
getdate()
作为运行时常量函数有关。因此 SQL Server 知道在查询执行开始时将其替换为常量。有没有办法可以将我自己的函数标记为运行时常量?
我尝试使用 CTE 首先获取日期,但这不知何故导致性能更差。
with dates as (select date_today_midnight() as today)
select * from aTable join dates on 1=1 where aDate >= dates.today;
-- runtime > 50s
不要使用您拥有的方法,自 SQL Server 2005 以来就不再需要它。
date
数据类型是在 SQL Server 2008 中添加的,因此没有理由使用像您这里这样的“古怪”解决方案。如果你想获取当前日期,作为日期,那么只需 CONVERT
/CAST
将值转换为 date
:
SELECT CONVERT(date,GETDATE()) AS CurrentDate;
至于使用函数,还是不要使用。众所周知,用户定义的标量函数性能不佳,因为从历史上看它们不是内联的。在 2019+(不是您正在使用的)中添加了可内联标量函数。然而,他们也遇到了性能问题,“解决方案”通常是微软添加越来越多的要求(警告)以导致函数内联。
您可以使用内联表值函数,但是,对于像这样琐碎的事情,完全不需要这样的函数。
CONVERT
/CAST
date
的值非常简单。
如果您使用的是 SQL Server 2022+,您还可以访问
DATETRUNC
函数:
SELECT DATETRUNC(DAY, GETDATE());
与
CONVERT
/CAST
不同,这将保留输入表达式的数据类型,因此将返回 2023-12-04T00:00:00.000
而不是 2023-12-04
。