我正在为ETL脚本创建一个存储过程,该脚本每小时运行一次,以便向用户提供特定操作的结果。
我需要找到当前结果的先前结果。这很好,我有一个工作查询,我导出到Excel。但是现在我希望自动化这个过程。
存储过程平均每次运行42秒。当在服务器上运行一小时时,这是不可行的,因为我还运行了其他自动脚本。
我的问题是存储过程的一小部分平均值为28秒,而其他所有内容通常只需不到一秒钟(在SSMS中显示为00:00:00)。
我设法减少了其他块的运行时间,我自己将其降低到平均42秒,但我无法做到这一点。
我想知道你们中是否有人知道加速这个小块的任何特定方法?
UPDATE #tmp
SET prev_test_date = (
SELECT TOP 1 r.test_date
FROM [dbo].[results] r (NOLOCK)
WHERE r.number = #tmp.number
AND r.test_date < #tmp.test_date
ORDER BY r.test_date DESC
)
我原本打算使用连接来加快速度,但由于查询的TOP 1部分,我无法做到这一点。
有什么想法吗?
答案 0 :(得分:2)
对于此查询:
UPDATE #tmp
SET prev_test_date = (
SELECT TOP 1 r.test_date
FROM [dbo].[results] r
WHERE r.number = #tmp.number AND
r.test_date < #tmp.test_date
ORDER BY r.test_date DESC
)
您需要r(number, test_date)
上的索引。
如果您使用的是SQL Server 2012+并且测试日期不重复,您也可以将其写为:
with r as (
select r.*,
lag(r.test_date) over (partition by r.number order by r.test_date desc) as prev_test_date
from [dbo].[results] r
)
update t
set t.prev_test_date = r.prev_test_date
from #tmp t join
r
on t.number = r.number;
实际上,如果是这种情况,您可能不需要临时表。您可以修改代码只是为了使用lag()
。
答案 1 :(得分:1)
UPDATE #tmp
SET #tmp.prev_test_date = tt.maxdate
from #tmp
join
(
select #tmp.number, max(r.test_date) maxdate
from #tmp
join [dbo].[results] r (NOLOCK)
on r.number = #tmp.number
AND r.test_date < #tmp.test_date
group by #tmp.number
) tt
on tt.number = #tmp.number
并且#tmp和[results]上的索引都在number,text_date
上答案 2 :(得分:1)
UPDATE #tmp
SET prev_test_date = (
SELECT max(r.test_date)
FROM [dbo].[results] r (NOLOCK)
WHERE r.number = #tmp.number
AND r.test_date < #tmp.test_date
)
如果没有更多信息,很难分辨,但如果处理过多,您可能需要制作单独的预先计算的表格,并在数据更改时逐步更新。
答案 3 :(得分:0)
我不得不对表格的结构和内容做一些假设,但如果我的假设是正确的,这就是我在这种情况下经常使用的方法:
with cteOrderedResults as (
-- Ideally R will be clustered by number, test_date for this
select R.number
,R.test_date
,row_number() over ( partition by R.number
order by R.test_date desc
-- So the most recent R.test_date from
-- before T.test_date gets RowNo=1
) as RowNo
from dbo.results R
inner join #tmp T on R.number=T.number
and R.test_date<T.test_date
)
update T
set T.prev_test_date=R.test_date
from #tmp T
inner join cteOrderedResults R on T.number=R.number
and 1=R.RowNo
对于我来说,这种方法对我来说很快就可以达到大约百万分之一的行集。正如我所评论的那样,我认为分区的row_number()将利用相应的聚簇索引(如果存在);如果你没有适当地聚集表,你可能会发现这不会那么快。
我同意此处其他地方的评论,如果您确定需要,则应该只添加nolock
提示。如果这样做,您应该使用完整正确的语法with (nolock)
。来自official MSDN page:
省略WITH关键字是一项不推荐使用的功能:此功能将在未来版本的Microsoft SQL Server中删除。