SQL Server如何避免WHERE子句中的时区转换

时间:2019-04-08 22:03:16

标签: sql-server query-optimization date-conversion

我必须检索特定日期 Pacific Standard Time 之间的行,但是数据库的date列存储为UTC。当前,我在WHERE子句中进行转换,但这需要花费很多时间,因为我在WHERE子句中使用了一个函数,这会导致全表扫描。

SELECT T.foo
FROM table T
JOIN .... ON ....
WHERE CONVERT(DATETIME,SWITCHOFFSET(T.start_date_utc,DATEPART(TZOFFSET, T.start_date_utc AT TIME ZONE 'Pacific Standard Time'))) BETWEEN '1/1/2018 00:00:00 AM' AND '2/28/2018 23:59:59 PM'

如果没有WHERE子句中的转换功能,还有更好的方法吗?

  • 查询需要30分钟,但是当我删除CONVERT而只有WHERE BETWEEN date1 AND date2时,它的运行速度要快得多,只有21秒。
  • 如果有比将转换语句与日期比较更好的解决方案,当然也欢迎其他建议。

其他信息:

  • 我仅具有CONNECT SQLVIEW ANY DATABASE权限,因此我不能创建任何新表,索引等。

  • 没有SHOWPLAN权限,我看不到查询执行计划来检查是否还有其他原因导致查询缓慢。但是由于取出convert语句将时间从30分钟缩短到21秒,所以我怀疑就是这一行。

  • 我正在使用Microsoft SQL Server Management Studio 17

  • Windows 7

我尝试过的事情:

  • 我尝试创建一个公共表并在主查询之前转换date列,但这仍然很慢。可能是因为转换仍然需要在每一行上进行。

    WITH CTE AS ( SELECT T.Foo, CONVERT(DATETIME,SWITCHOFFSET(T.start_date_utc, DATEPART(TZOFFSET, T.start_date_utc AT TIME ZONE 'Pacific Standard Time'))) as start_date_pst

2 个答案:

答案 0 :(得分:2)

另一种方法是将您的输入更改为UTC。这是一次操作,SQL筛选起来更容易。根据您的sql版本,以下是实现相同目标的不同方法。

-- 1
WHERE T.start_date_utc
     BETWEEN '1/1/2018 08:00:00 AM' /*PST to UTC*/
        AND '2/28/2018 07:59:59 PM' /*PST to UTC*/
-- 2    
WHERE T.start_date_utc
 BETWEEN DATEADD(HOUR, 8, '1/1/2018 00:00:00 AM'),  /*PST to UTC*/
    AND DATEADD(HOUR, 8, '2/28/2018 23:59:59 PM' /*PST to UTC*/

-- 3
WHERE T.start_date_utc
     BETWEEN SWITCHOFFSET('1/1/2018 00:00:00 AM', '-08:00') /*PST to UTC*/
        AND SWITCHOFFSET('2/28/2018 23:59:59 PM', '-08:00') /*PST to UTC*/


/*Avoiding hard coded values*/

-- 4
DECLARE @offset INT

 SELECT @offset = DATEPART(TZOFFSET, CONVERT(datetime,'1/1/2018 00:00:00 AM') AT TIME ZONE 'Pacific Standard Time') * -1

 WHERE T.start_date_utc
 BETWEEN DATEADD(MINUTE, @offset, '1/1/2018 00:00:00 AM'),  /*PST to UTC*/
    AND DATEADD(MINUTE, @offset, '2/28/2018 23:59:59 PM' /*PST to UTC*/

-- 5        
WHERE T.start_date_utc
     BETWEEN CONVERT(datetime,'1/1/2018 00:00:00 AM')  AT TIME ZONE 'Pacific Standard Time' /*PST to UTC*/
        AND CONVERT(datetime,'2/28/2018 23:59:59 PM')  AT TIME ZONE 'Pacific Standard Time' /*PST to UTC*/

答案 1 :(得分:1)

现在,您正在对所有数据进行时区转换。相反,找出正确的UTC时间戳应该是一次,然后将您的数据与之进行比较。像这样:

declare @startTimePST datetime = '1/1/2018 00:00:00 AM',
    @endTimePST datetime = '2/28/2018 23:59:59 PM';

declare @startTimeUTC datetime = @startTimePST 
    at time zone 'Pacific Standard Time' 
    at time zone 'UTC',
  @endTimeUTC datetime = @endTimePST 
    at time zone 'Pacific Standard Time' 
    at time zone 'UTC';

select @startTimePST, @startTimeUTC, 
    @endTimePST, @endTimeUTC

SELECT T.foo
FROM table T
JOIN .... ON ....
WHERE T.start_date_utc BETWEEN @startTimeUTC AND @endTimeUTC;

通过阐述的方式,我要声明变量并为它们分配表示您的PST时间戳记的值。然后,我通过重复使用at time zone子句将其转换为UTC。为什么要两个?第一个将PST时区附加到您的无时区时间戳上,然后将那些转换为UTC。一旦有了这些端点,就可以直接在查询中使用它们。