Maz*_*har 5 performance sql-server sql-server-2008-r2 set-returning-functions query-performance
我为 GMT 地区创建了一个“夏令时”查找日历表。我用来查询表以从 UTC 日期时间返回本地日期时间的函数性能不佳。
任何有助于改善这一点的帮助,包括改变 TVF 的编码方式,将不胜感激。
该函数将用于可以频繁返回 1m+ 行的查询。该函数用于查询包含行程数据的仓库表。
行程的开始和结束日期时间以 UTC 格式存储,上面的函数用于将它们转换为本地时间。一位早已离开公司的开发人员编写了一个将 UTC 时间转换为本地时间的标量函数。我的任务是使用日历表和 TVF 重写该函数,因为 TVF 的性能应该比标量函数更好
没有功能:
SQL Server Execution Times: CPU time = 4633 ms, elapsed time = 4909 ms.
Run Code Online (Sandbox Code Playgroud)
具有以下功能:
SQL Server Execution Times: CPU time = 20795 ms, elapsed time = 21176 ms.
Run Code Online (Sandbox Code Playgroud)
这是表中的示例输出
CREATE TABLE dbo.DSTLookup
(
[Id] int,
[Tzid] int,
[DT_WhenSwitch] datetime,
[DSTOffSetSeconds] int,
[GMTOffSetSeconds] int
)
INSERT INTO dbo.DSTLookup
VALUES (29, 2, N'2014-03-30T01:00:00', 3600, 0),
(30, 2, N'2014-10-26T02:00:00', 0, 0),
(31, 2, N'2015-03-29T01:00:00', 3600, 0),
(32, 2, N'2015-10-25T02:00:00', 0, 0),
(33, 2, N'2016-03-27T01:00:00', 3600, 0),
(34, 2, N'2016-10-30T02:00:00', 0, 0),
(35, 2, N'2017-03-26T01:00:00', 3600, 0),
(36, 2, N'2017-10-29T02:00:00', 0, 0),
(37, 2, N'2018-03-25T01:00:00', 3600, 0),
(38, 2, N'2018-10-28T02:00:00', 0, 0)
Run Code Online (Sandbox Code Playgroud)
这是TVF:
CREATE FUNCTION dbo.FN_GetLocalTime_FromUTC_BasedOnTZId
(@StartDateTime DATETIME, @EndDateTime DATETIME, @Tzid INT)
/*=========================================================================
* 2017-03-27
* Returns local time from UTC time based on timeZoneId
*
==========================================================================*/
RETURNS TABLE
AS
RETURN
(
WITH cteStartDate AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY D.Id DESC),
D.DSTOffSetSeconds 's_DST_OffSet',
D.GMTOffSetSeconds 's_GMT_OffSet'
FROM
dbo.DSTLookup D
WHERE
D.DT_WhenSwitch <= @StartDateTime
AND D.Tzid = @Tzid
),
cteEndDate AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY D.Id DESC),
D.DSTOffSetSeconds 'e_DST_OffSet',
D.GMTOffSetSeconds 'e_GMT_OffSet'
FROM
dbo.DSTLookup D
WHERE
D.DT_WhenSwitch <= @EndDateTime
AND D.Tzid = @Tzid
),
cteConvertStartDate AS
(
SELECT
DATEADD(SECOND, (COALESCE(S.s_DST_OffSet, 0) + COALESCE(S.s_GMT_OffSet, 0)), @StartDateTime) 'LocalStartDateTime'
FROM
cteStartDate S
WHERE
S.RN = 1
),
cteConvertEndDate AS
(
SELECT
DATEADD(SECOND, (COALESCE(E.e_DST_OffSet, 0) + COALESCE(E.e_GMT_OffSet, 0)), @EndDateTime) 'LocalEndDateTime'
FROM
cteEndDate E
WHERE
E.RN = 1
)
SELECT
S.LocalStartDateTime, E.LocalEndDateTime
FROM
cteConvertStartDate S, cteConvertEndDate E
);
GO
Run Code Online (Sandbox Code Playgroud)
要查询 TVF:
SELECT *
FROM dbo.FN_GetLocalTime_FromUTC_BasedOnTzId
('2017-03-27 10:00:30', '2017-03-27 10:15:54', 2);
Run Code Online (Sandbox Code Playgroud)
执行计划遵循 Max 的建议以包含主键。
WITH SCHEMABINDING
通过添加到子句,使您的函数成为架构绑定的表值函数RETURNS TABLE
。
所以:
CREATE FUNCTION dbo.FN_GetLocalTime_FromUTC_BasedOnTZId
(@StartDateTime DATETIME, @EndDateTime DATETIME, @Tzid INT)
/*=========================================================================
* 2017-03-27
* Returns local time from UTC time based on timeZoneId
*
==========================================================================*/
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
WITH cteStartDate AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY D.Id DESC),
D.DSTOffSetSeconds 's_DST_OffSet',
D.GMTOffSetSeconds 's_GMT_OffSet'
FROM
dbo.DSTLookup D
WHERE
D.DT_WhenSwitch <= @StartDateTime
AND D.Tzid = @Tzid
),
cteEndDate AS
(
SELECT
RN = ROW_NUMBER() OVER (ORDER BY D.Id DESC),
D.DSTOffSetSeconds 'e_DST_OffSet',
D.GMTOffSetSeconds 'e_GMT_OffSet'
FROM
dbo.DSTLookup D
WHERE
D.DT_WhenSwitch <= @EndDateTime
AND D.Tzid = @Tzid
),
cteConvertStartDate AS
(
SELECT
DATEADD(SECOND, (COALESCE(S.s_DST_OffSet, 0) + COALESCE(S.s_GMT_OffSet, 0)), @StartDateTime) 'LocalStartDateTime'
, S.RN
FROM
cteStartDate S
WHERE
S.RN = 1
),
cteConvertEndDate AS
(
SELECT
DATEADD(SECOND, (COALESCE(E.e_DST_OffSet, 0) + COALESCE(E.e_GMT_OffSet, 0)), @EndDateTime) 'LocalEndDateTime'
, E.RN
FROM
cteEndDate E
WHERE
E.RN = 1
)
SELECT
S.LocalStartDateTime, E.LocalEndDateTime
FROM
cteConvertStartDate S
INNER JOIN cteConvertEndDate E ON S.RN = E.RN
);
Run Code Online (Sandbox Code Playgroud)
这允许查询处理器“内联”该函数。这允许进行多项优化,其中最重要的是能够正确理解函数中引用的对象的统计信息。
向表添加聚集索引dbo.DSTLookup
。这允许查询执行查找而不是扫描。对于示例数据中的行数,这可能不会产生很大的差异,但对于真实的表,它可能会产生很大的差异。
由于您有一Id
列似乎是单调递增的整数,因此也许这是用作聚集主键的良好候选键:
CREATE TABLE dbo.DSTLookup
(
[Id] int
CONSTRAINT PK_DSTLookup
PRIMARY KEY CLUSTERED,
[Tzid] int,
[DT_WhenSwitch] datetime,
[DSTOffSetSeconds] int,
[GMTOffSetSeconds] int
);
Run Code Online (Sandbox Code Playgroud)
我会考虑根据您的 TVF 添加以下索引:
CREATE INDEX IX_DSTLookup_001
ON dbo.DSTLookup (DT_WhenSwitch, Tzid)
INCLUDE (DSTOffSetSeconds, GMTOffSetSeconds);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
962 次 |
最近记录: |