SQL服务器:如何运行每小时查询一次,并将结果存储在table中?在更新时替换它们
SQL Server: How to run a query every hour, and store results in a table? Replace them on update
我有一个耗时 5 分钟的繁重查询,我想将其结果存储在 table 中,后端将对其进行查询。
此外,table 应该每小时更新一次,并用新数据完全替换 table 的内容。
我找到了 this Server Agent solution,根据我的理解,我应该这样做:
- 创建结果 table。
- 创建删除结果 table 数据的存储过程,运行 5 分钟的查询,然后插入新数据。
- 创建每隔一段时间运行该过程的服务器代理作业。
这是最佳方式吗?
这是有问题的查询。它超过了很多行,我认为这是主要的速度影响因素。
WITH
salesCTE AS (
select
concat(year(m.addate), '-', format(m.addate, 'MM')) AS ym,
year(m.addate) as y,
format(m.addate, 'MM') as m,
sum(M.anvalue) as salesRev
FROM tHE_Move m
WHERE (
RIGHT(LEFT(M.acKey,5),3) = '300'
OR RIGHT(LEFT(M.acKey,5),3) = '305'
OR RIGHT(LEFT(M.acKey,5),3) = '319'
OR RIGHT(LEFT(M.acKey,5),3) = '380'
OR RIGHT(LEFT(M.acKey,5),3) = '355'
OR RIGHT(LEFT(M.acKey,5),3) = '360'
OR RIGHT(LEFT(M.acKey,5),3) = '3X1'
OR RIGHT(LEFT(M.acKey,5),3) = '395'
) and m.adDate between '01.01.2014' and '01.01.2030'
GROUP BY
concat(year(m.addate), '-', format(m.addate, 'MM')),
year(m.addate),
format(m.addate, 'MM')
),
retailCTE AS (
select
concat(year(m.addate), '-', format(m.addate, 'MM')) AS ym,
year(m.addate) as y,
format(m.addate, 'MM') as m,
sum(M.anvalue) as retailRev
FROM tHE_Move m
where (
RIGHT(LEFT(M.acKey,5),3) = '321'
OR RIGHT(LEFT(M.acKey,5),3) = '322'
OR RIGHT(LEFT(M.acKey,5),3) = '323'
OR RIGHT(LEFT(M.acKey,5),3) = '324'
OR RIGHT(LEFT(M.acKey,5),3) = '325'
OR RIGHT(LEFT(M.acKey,5),3) = '326'
OR RIGHT(LEFT(M.acKey,5),3) = '327'
OR RIGHT(LEFT(M.acKey,5),3) = '328'
OR RIGHT(LEFT(M.acKey,5),3) = '329'
OR RIGHT(LEFT(M.acKey,5),3) = '331'
OR RIGHT(LEFT(M.acKey,5),3) = '332'
OR RIGHT(LEFT(M.acKey,5),3) = '333'
OR RIGHT(LEFT(M.acKey,5),3) = '334'
OR RIGHT(LEFT(M.acKey,5),3) = '335'
OR RIGHT(LEFT(M.acKey,5),3) = '336'
OR RIGHT(LEFT(M.acKey,5),3) = '337'
OR RIGHT(LEFT(M.acKey,5),3) = '338'
OR RIGHT(LEFT(M.acKey,5),3) = '339'
OR RIGHT(LEFT(M.acKey,5),3) = '341'
OR RIGHT(LEFT(M.acKey,5),3) = '342'
OR RIGHT(LEFT(M.acKey,5),3) = '343'
OR RIGHT(LEFT(M.acKey,5),3) = '344'
OR RIGHT(LEFT(M.acKey,5),3) = '345'
OR RIGHT(LEFT(M.acKey,5),3) = '346'
OR RIGHT(LEFT(M.acKey,5),3) = '347'
OR RIGHT(LEFT(M.acKey,5),3) = '348'
OR RIGHT(LEFT(M.acKey,5),3) = '349'
OR RIGHT(LEFT(M.acKey,5),3) = '352'
OR RIGHT(LEFT(M.acKey,5),3) = '353'
) and m.adDate between '01.01.2014' and '01.01.2030'
GROUP BY
concat(year(m.addate), '-', format(m.addate, 'MM')),
year(m.addate),
format(m.addate, 'MM')
)
SELECT
s1.ym,
s1.salesRev,
(s1.salesRev / s2.salesRev - 1) * 100 salesDelta,
r1.retailRev,
(r1.retailRev / r2.retailRev - 1) * 100 retailDelta,
s1.salesRev + r1.retailRev totalRev,
((s1.salesRev + r1.retailRev) / (s2.salesRev + r2.retailRev) - 1) * 100 totalDelta
FROM salesCTE s1
left join salesCTE s2
on s2.y = s1.y - 1 and s1.m = s2.m
left join retailCTE r1
on s1.ym = r1.ym
left join retailCTE r2
on r2.y = r1.y - 1 and r1.m = r2.m
order by s1.ym desc
正如评论中提到的 FORMAT
是一个巨大的性能击球手;而我的大量我确实意味着大量。以 DB<>Fiddle 为例,它使用 FORMAT
和 CONVERT
来更改日期的值。使用 CONVERT
的查询执行时间为 46 毫秒(在数据库 fiddle 上),但 FORMAT
查询花费了 1218 毫秒!那慢了 26 倍。
将 format(m.addate, 'MM')
更改为 RIGHT('00' + CONVERT(varchar(2),DATEPART(MONTH,DATEADD(DAY,N-1,0))),2)
将显着提高您的查询性能。尽管后者看起来更复杂,但它(如 fiddle 所示)将大大优于 FORMAT
。 老实说,我建议永远不要使用 FORMAT
,Microsoft 在该功能上确实有问题。
不过,我也建议将 RIGHT(LEFT(M.acKey,5),3)
作为持久列添加到您的 table:
ALTER TABLE tHE_Move ADD {Meaningful Name} AS RIGHT(LEFT(M.acKey,5),3) PERSISTED;
然后您还可以将该值添加到索引(新的或现有的)中,这也会大大提高查询的性能;也许将它推到只有几秒钟。
我有一个耗时 5 分钟的繁重查询,我想将其结果存储在 table 中,后端将对其进行查询。
此外,table 应该每小时更新一次,并用新数据完全替换 table 的内容。
我找到了 this Server Agent solution,根据我的理解,我应该这样做:
- 创建结果 table。
- 创建删除结果 table 数据的存储过程,运行 5 分钟的查询,然后插入新数据。
- 创建每隔一段时间运行该过程的服务器代理作业。
这是最佳方式吗?
这是有问题的查询。它超过了很多行,我认为这是主要的速度影响因素。
WITH
salesCTE AS (
select
concat(year(m.addate), '-', format(m.addate, 'MM')) AS ym,
year(m.addate) as y,
format(m.addate, 'MM') as m,
sum(M.anvalue) as salesRev
FROM tHE_Move m
WHERE (
RIGHT(LEFT(M.acKey,5),3) = '300'
OR RIGHT(LEFT(M.acKey,5),3) = '305'
OR RIGHT(LEFT(M.acKey,5),3) = '319'
OR RIGHT(LEFT(M.acKey,5),3) = '380'
OR RIGHT(LEFT(M.acKey,5),3) = '355'
OR RIGHT(LEFT(M.acKey,5),3) = '360'
OR RIGHT(LEFT(M.acKey,5),3) = '3X1'
OR RIGHT(LEFT(M.acKey,5),3) = '395'
) and m.adDate between '01.01.2014' and '01.01.2030'
GROUP BY
concat(year(m.addate), '-', format(m.addate, 'MM')),
year(m.addate),
format(m.addate, 'MM')
),
retailCTE AS (
select
concat(year(m.addate), '-', format(m.addate, 'MM')) AS ym,
year(m.addate) as y,
format(m.addate, 'MM') as m,
sum(M.anvalue) as retailRev
FROM tHE_Move m
where (
RIGHT(LEFT(M.acKey,5),3) = '321'
OR RIGHT(LEFT(M.acKey,5),3) = '322'
OR RIGHT(LEFT(M.acKey,5),3) = '323'
OR RIGHT(LEFT(M.acKey,5),3) = '324'
OR RIGHT(LEFT(M.acKey,5),3) = '325'
OR RIGHT(LEFT(M.acKey,5),3) = '326'
OR RIGHT(LEFT(M.acKey,5),3) = '327'
OR RIGHT(LEFT(M.acKey,5),3) = '328'
OR RIGHT(LEFT(M.acKey,5),3) = '329'
OR RIGHT(LEFT(M.acKey,5),3) = '331'
OR RIGHT(LEFT(M.acKey,5),3) = '332'
OR RIGHT(LEFT(M.acKey,5),3) = '333'
OR RIGHT(LEFT(M.acKey,5),3) = '334'
OR RIGHT(LEFT(M.acKey,5),3) = '335'
OR RIGHT(LEFT(M.acKey,5),3) = '336'
OR RIGHT(LEFT(M.acKey,5),3) = '337'
OR RIGHT(LEFT(M.acKey,5),3) = '338'
OR RIGHT(LEFT(M.acKey,5),3) = '339'
OR RIGHT(LEFT(M.acKey,5),3) = '341'
OR RIGHT(LEFT(M.acKey,5),3) = '342'
OR RIGHT(LEFT(M.acKey,5),3) = '343'
OR RIGHT(LEFT(M.acKey,5),3) = '344'
OR RIGHT(LEFT(M.acKey,5),3) = '345'
OR RIGHT(LEFT(M.acKey,5),3) = '346'
OR RIGHT(LEFT(M.acKey,5),3) = '347'
OR RIGHT(LEFT(M.acKey,5),3) = '348'
OR RIGHT(LEFT(M.acKey,5),3) = '349'
OR RIGHT(LEFT(M.acKey,5),3) = '352'
OR RIGHT(LEFT(M.acKey,5),3) = '353'
) and m.adDate between '01.01.2014' and '01.01.2030'
GROUP BY
concat(year(m.addate), '-', format(m.addate, 'MM')),
year(m.addate),
format(m.addate, 'MM')
)
SELECT
s1.ym,
s1.salesRev,
(s1.salesRev / s2.salesRev - 1) * 100 salesDelta,
r1.retailRev,
(r1.retailRev / r2.retailRev - 1) * 100 retailDelta,
s1.salesRev + r1.retailRev totalRev,
((s1.salesRev + r1.retailRev) / (s2.salesRev + r2.retailRev) - 1) * 100 totalDelta
FROM salesCTE s1
left join salesCTE s2
on s2.y = s1.y - 1 and s1.m = s2.m
left join retailCTE r1
on s1.ym = r1.ym
left join retailCTE r2
on r2.y = r1.y - 1 and r1.m = r2.m
order by s1.ym desc
正如评论中提到的 FORMAT
是一个巨大的性能击球手;而我的大量我确实意味着大量。以 DB<>Fiddle 为例,它使用 FORMAT
和 CONVERT
来更改日期的值。使用 CONVERT
的查询执行时间为 46 毫秒(在数据库 fiddle 上),但 FORMAT
查询花费了 1218 毫秒!那慢了 26 倍。
将 format(m.addate, 'MM')
更改为 RIGHT('00' + CONVERT(varchar(2),DATEPART(MONTH,DATEADD(DAY,N-1,0))),2)
将显着提高您的查询性能。尽管后者看起来更复杂,但它(如 fiddle 所示)将大大优于 FORMAT
。 老实说,我建议永远不要使用 FORMAT
,Microsoft 在该功能上确实有问题。
不过,我也建议将 RIGHT(LEFT(M.acKey,5),3)
作为持久列添加到您的 table:
ALTER TABLE tHE_Move ADD {Meaningful Name} AS RIGHT(LEFT(M.acKey,5),3) PERSISTED;
然后您还可以将该值添加到索引(新的或现有的)中,这也会大大提高查询的性能;也许将它推到只有几秒钟。