the*_*n B 5 sql-server locking merge
我有一个需要每天更新的 SQL 表。更新发生时可能会或可能不会对该表进行查询。大约有 500,000 行。
我们遇到一个问题,当更新表的作业与针对表的查询同时运行时,会出现锁定冲突。
所以我重写了更新表的流程如下:
ALTER procedure [dbo].[Table_Generate] as
declare @d datetime = getdate(), @c as int
--Check temp tables
IF OBJECT_ID('tempdb..#final') IS NOT NULL
DROP TABLE #final
IF OBJECT_ID('tempdb..#base') IS NOT NULL
DROP TABLE #base
--Get source data from linked server
select
ID,
Reference,
StartDate,
EndDate,
Description,
SomeCode
into #base
from [LinkedServer].[Database].dbo.[A_View]
--Generate row_hash
select
ID,
Reference,
StartDate,
EndDate,
Description,
SomeCode,
hashbytes('SHA2_256',(
select
ID,
Reference,
StartDate,
EndDate,
Description,
SomeCode
from #base sub where sub.ID = main.ID for xml raw)) as row_hash
into #final
from #base main
select @c = count(*) from #final
if @c >0 begin
merge [The_Table_Staging] as target
using #final as source
on source.ID = target.ID
--New rows
when not matched by target then
insert ( RunDate,
ID,
Reference,
StartDate,
EndDate,
Description,
SomeCode,
Row_Hash
) values (
@d,
source.ID,
source.Reference,
source.StartDate,
source.EndDate,
source.Description,
source.SomeCode,
source.row_hash)
--Existing changed rows
when matched and source.row_hash != target.row_hash then update set
target.RunDate = @d
,target.Reference = source.Reference
,target.StartDate = source.StartDate
,target.EndDate = source.EndDate
,target.Description = source.Description
,target.SomeCode = source.SomeCode
,target.row_hash = source.row_hash
--Deleted rows
when not matched by source then delete;
--Existing unchanged rows
update [The_Table_Staging] set RunDate = @d where RunDate != @d
--Commit changes
begin transaction
exec sp_rename 'The_Table_Live', 'The_Table_Staging_T'
exec sp_rename 'The_Table_Staging', 'The_Table_Live'
exec sp_rename 'The_Table_Staging_T', 'The_Table_Staging'
commit transaction
end
Run Code Online (Sandbox Code Playgroud)
其想法是减少不必要的行更新,并最大限度地减少活动表的锁定。我不太喜欢执行表重命名,但执行更新/插入需要 5-10 秒,而表重命名几乎是瞬时的。
所以我的问题是:这种方法可以吗?和/或者我可以改进它吗?
谢谢!
编辑回复JD:
嗨,JD,请不必道歉 - 我来这里是为了提出建设性的批评。
MERGE
有问题。我自己从来没有遇到过问题,但谢谢INSERT/UPDATE/DELETE
语句TRUNCATE/INSERT
在此时进行 from staging,则需要 6-10 秒,而普通版则sp_rename
需要不到一秒。因此锁定表的时间更少XML
而不是CONCAT
因为否则'a','bc'将散列与'ab','c'相同,这是不正确的从暂存到填充活动表的所有处理都很好 - 我只是想最大限度地减少最终活动表被锁定的时间,
不幸的是,我一眼就看到你的代码中有很多错误:
有大量已知的错误表明MERGE
在生产代码中确实应该完全避免它。
MERGE
众所周知,其性能不如编写单独的INSERT
、UPDATE
和DELETE
语句;这可能是一些阻塞问题的原因。
虽然很诱人,但使用该sp_rename
函数来最小化阻塞问题实际上可能会导致更严重的阻塞问题,正如 Kendra Little 的《为什么你应该在暂存表中切换而不是重命名它们》中所讨论的那样。(如果我没记错的话,本文讨论了使用分区切换作为更好的解决方案。)
众所周知,链接服务器有时也会成为性能瓶颈(对于固定基数估计以及在处理之前将所有数据传输到网络)。如果您之前在代码事务中依赖它,则可以将该部分保留在事务之外,以最大限度地减少本地表的锁定时间。
另外,我确实喜欢使用该HASHBYTES()
函数来生成行哈希,这是我过去使用过的。CONCAT()
但您也可能会发现,通过在每列上使用安全列分隔符(例如双管道||
)作为参数来在行本身上调用它,而不是在利用 XML 的子查询中使用它,性能会更高。
话虽如此,正如 Erik Darling 所指出的那样,HASHBYTES()
它本身有时很容易受到大规模性能问题的影响。如果这是您的瓶颈,您可以尝试在计算列或索引视图中具体化函数的结果(它是确定性的),或者使用替代方法,例如 CLR,如链接文章中所述。
归档时间: |
|
查看次数: |
723 次 |
最近记录: |