在一天的特定时间之后-哪种方法更好?

时间:2019-05-14 14:56:40

标签: sql-server

我需要知道(并标记)子查询中的特定事件是否在下午3:30之后发生(无论日期如何)。
对于我的设置,我无法通过试用来确定哪种效率更高(它们回来得太快),并且执行计划没有帮助。

第二个(#2)在我看来似乎更有效率,因为文字只需要强制转换一次(每行只保留一个操作)。
但是,有时像这样的操作在欺骗,所以我希望有人可以告诉我哪个更好。

CREATE TABLE #jccTestData([ProcessDate] datetime);
INSERT INTO #jccTestData ([ProcessDate])
VALUES 
    ('2019-03-12 10:23:28.000') ,('2019-03-17 11:22:40.000'), ('2019-03-18 11:25:30.000')
    ,('2019-03-19 11:42:02.000') ,('2019-03-11 12:45:30.000') ,('2019-03-12 13:14:20.000')
    ,('2019-03-13 15:20:13.000') ,('2019-03-14 15:29:40.000') ,('2019-03-15 15:29:59.997') 
    ,('2019-03-16 15:30:00.000') ,('2019-03-17 15:30:00.003') ,('2019-03-18 16:25:30.000')
    ,('2019-03-12 23:59:59.997') ,('2019-03-13 00:00:00.003') ,('2019-03-14 00:00:00.000')
    ,('2019-03-15 03:14:20.000') ,('2019-03-16 05:20:13.000')

SELECT 
    [ProcessDate]
    , Case When datepart(HH, [ProcessDate]) > 15
        OR (datepart(HH, [ProcessDate]) = 15 And datepart(n, [ProcessDate]) >= 30) 
        Then 'After 3:30 PM' 
        End As [After 3:30? #1]
    , Case When cast([ProcessDate] As time) >= cast('15:30:00' As time) 
        Then 'After 3:30 PM' 
        End As [After 3:30? #2]
FROM #jccTestData  
ORDER BY [ProcessDate]

DROP TABLE #jccTestData

第二个也似乎更易于维护。

如果还有第三种选择,我也愿意接受。
SQL Server 2012以上版本

3 个答案:

答案 0 :(得分:2)

就个人而言,如果可以的话,我实际上会向表中添加一个计算列。如果使用该路由,CONVERT / CASTtime数据类型绝对是必经之路,但是如果您可以添加一个持久化的计算列,则可以对该列建立索引或添加它到您现有的表中,并且如果您需要在WHERE中查询此数据,则保持SARGability(我知道这里的示例是一个临时表,但我怀疑实际情况是这样):

ALTER TABLE #jccTestData ADD ProcessTime AS CONVERT(time,ProcessDate) PERSISTED;

然后,您可以查询新列:

SELECT [ProcessDate],
       CASE WHEN ProcessTime >= '03:30' THEN 'After 3:30 PM' END AS [After 3:30?]
FROM #jccTestData
ORDER BY [ProcessDate];

此外,避免对ORDER BY中的列使用序数,最好使用列的实际名称。

旁注,您无需具有用于强制转换/转换为date数据类型的列。 CONVERT(date,ProcessDate)CAST(ProcessDate AS date)均可保存。

答案 1 :(得分:2)

由于您在询问效率,因此我对超过一百万条真实记录进行了一些基准测试。下面的最后一种方法(CAST)报告更多的CPU时间。所有时间都是毫秒,因此您需要数百万条记录才能注意到任何差异。

IIF((DATEPART(HH, dateStamp) * 60) + DATEPART(MINUTE, dateStamp) >= 930, 'After 3:30 PM', '')
IIF(DATEPART(HH, dateStamp) > 15 OR (DATEPART(HH, dateStamp) = 15 AND DATEPART(N, dateStamp) >= 30), 'After 3:30 PM', '')
IIF(CAST(dateStamp AS TIME) >= CAST('15:30:00' AS TIME), 'After 3:30 PM', '')

1)平均CPU时间:477;平均经过时间:242

2)平均CPU时间:469;平均经过时间:236

3)平均CPU时间:808;平均经过时间:413

答案 2 :(得分:0)

如果您确实不更改apply结构,我将使用第三个选项DB

SELECT d.[ProcessDate],
       (CASE WHEN dd.ProcessTime >= '15:30' THEN 'After 3:30 PM' END) AS [After 3:30?]
FROM #jccTestData d CROSS APPLY
     ( VALUES (CONVERT(TIME, ProcessDate)) 
     ) dd (ProcessTime )
ORDER BY d.[ProcessDate];