日期截断的包装函数

问题描述 投票:0回答:1

我不喜欢在 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 sql-server-2017
1个回答
2
投票

不要使用您拥有的方法,自 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

© www.soinside.com 2019 - 2024. All rights reserved.