SQL Server Sql,有没有更有效的方法将日期时间转换为不同的时区?

dsf9zpds  于 2022-11-21  发布在  其他
关注(0)|答案(2)|浏览(185)

I have a table called AuditLogs that has a log of every single user action and their timestamp.
All these timestamp logs are recorded in UTC with a time offset of zero. While the actual users performing these actions are in California, with UTC-8.
I am trying to write a report with this data, and all the data needs to be in Californa time, to correctly contextualize when users are performing certain actions.
This is what my query looks like

select distinct top 1000
    Users.FirstName + ' ' + Users.LastName Name
    ,AuditRecords.username
    ,AuditRecords.subtype
    ,convert(varchar, timestamp at time zone 'Pacific Standard Time', 0)  time
    ,timestamp

from 
    AuditRecords 
    join Users on AuditRecords.UserId = Users.Id
where 
    AuditRecords.subtype <> 'log%'
    and DATEPART(dy,timestamp at time zone 'Pacific Standard Time') = datepart(dy,SYSDATETIMEOFFSET() at time zone 'Pacific Standard Time')-1

With the key line being

and DATEPART(dy,timestamp at time zone 'Pacific Standard Time') = datepart(dy,SYSDATETIMEOFFSET() at time zone 'Pacific Standard Time')-1

With that line, I am trying to retrieve all records from the previous date, not based on a rolling 24 hours. For example, if the report is run on November 9th, it doesn't matter if the report was run at 6 AM or 6 PM, it will return all records for November 8th.
The problem is, if I change that line to be without the

at time zone 'Pacific Standard Time'

in both places, the query runs a lot faster. However, when the time is adjusted to the correct timezone with that line, then the query becomes a lot slower.
Is there any more efficient way to do this?
Thanks a lot for any advice.

6ie5vjzr

6ie5vjzr1#

示例:

Declare @startDate datetimeoffset = dateadd(day, datediff(day, 0, sysdatetime()) - 1, 0) At Time Zone 'Pacific Standard Time'

 Select @startDate
      , @startDate At Time Zone 'UTC'

select distinct top 1000
    Users.FirstName + ' ' + Users.LastName Name
    ,AuditRecords.username
    ,AuditRecords.subtype
    ,convert(varchar, timestamp at time zone 'Pacific Standard Time', 0)  time
    ,timestamp
from 
    AuditRecords 
    join Users on AuditRecords.UserId = Users.Id
where 
    AuditRecords.subtype <> 'log%'
    and timestamp >= @startDate At Time Zone 'UTC'
    and timestamp <  dateadd(day, 1, @startDate) At Time Zone 'UTC'

此外,不要在where子句中对列使用函数,因为这会阻止SQL Server使用该列的索引。
还有一件事-你的逻辑在1月1日不起作用,因为一年中的第一天是1,1 - 1等于0,所以没有匹配。
您也要小心定义开始日期。如果您尝试使用UTC,可能会在错误的日期执行报表,这取决于执行报表的时间和执行报表的执行严修位移。

6l7fqoea

6l7fqoea2#

我们将性能问题的范围缩小到以下表达式:

DATEPART(dy,timestamp at time zone 'Pacific Standard Time') = 
    datepart(dy,SYSDATETIMEOFFSET() at time zone 'Pacific Standard Time')-1

这个问题还告诉我们,数据存储在UTC中,并且我们知道(通过注解)服务器在NY中运行。
首先,这是一个糟糕的做法。您的服务器应该使用与数据相同的时区运行。许多人会告诉您,这意味着始终保持所有UTC时间,但我并不认为这是一个极端。如果您的业务完全在加州州,并且您的数据存储在加利福尼亚州时间的日期时间字段中,使用相同的时区运行服务器可能是合适的。但如果数据以UTC存储,则数据库服务器也应该运行UTC时间,* 无论服务器位于何处 *。(我说“修复”,因为你所拥有的真的是坏了)会完全修复问题中的问题。
但预计使修复将脱离你的手,我们仍然可以帮助事情有点。
只要您有一个WHERE条件表达式,其中一端涉及表中的列,而另一端不涉及,您总是会获得更好的性能,使所有调整表达式中不引用任何列的那一端。这并不接近......我们谈论的是多个数量级的差异。
这意味着你要做 * 任何事情 * 来得到这个表达式的问题看起来像这样:

timestamp = SOME_COMPLICATED_AND_LONG_EXPRESSION_HERE( SYSDATETIMEOFFSET() )

这样做的最大好处是可以使用timestamp列中的索引。如果必须对表达式的timestamp侧进行调整,就不再需要使用与索引相同的值。这就切入了数据库性能的核心,而且 * 将 * 产生 * 昼夜 * 差异。
更糟糕的是,如果您无法做到这一点,那么对timestamp列所做的任何操作都必须针对表中的每一行进行计算......甚至是您不需要的行,因为服务器在完成转换之前无法知道是否将使用给定的值。
在这种情况下,您可能无法避免表达式中的DATEPART(dy...)部分。但是您可以将表达式右侧的时间从纽约时间调整为UTC时间。这将使您跳过左侧的at time zone部分,这本身将是一个 * 巨大 * 的帮助。这里值得注意的是,由于政府对时间的干预,这些时区调整查找要比您想象的复杂得多。将其缩减为一个总时区调整可以大大改进查询,而不必对每一行进行调整。

相关问题