我有一个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
这样做的目的是减少不必要的行更新,并尽量减少活动表的锁定。我不太喜欢做表重命名,但是执行更新/插入需要5-10秒,而表重命名几乎是瞬间的。
所以我的问题是:这种方法可以吗?或者我可以改进它?
谢谢!
的响应
嗨,JD,请不要道歉--我是来接受建设性的批评的。
MERGE
有问题。我自己也从来没出过问题,但是谢谢INSERT/UPDATE/DELETE
语句。TRUNCATE/INSERT
,它需要6-10秒,而sp_rename
需要不到1秒。所以锁表的时间更短了XML
而不是CONCAT
,因为否则'a','bc‘将与'ab','c’一样散列,这是不正确的。从暂存到填充活动表的所有处理都很好--我只想尽量减少最后的活动表锁定的时间,
发布于 2022-05-17 18:49:40
不幸的是,在您的代码中,我一眼就看到了许多错误:
MERGE
语句。MERGE
的性能不如编写单独的INSERT
、UPDATE
和DELETE
语句,这可能是导致某些阻塞问题的原因。sp_rename
函数来最小化阻塞问题实际上会导致更糟糕的阻塞问题,正如Kendra的为什么要切换暂存表而不是重命名它们中所讨论的那样。(如果我没有记错的话,这将讨论使用分区切换作为更好的解决方案。)HASHBYTES()
函数来生成行哈希,这是我过去使用过的。但是,您还可能会发现在行本身上调用它的性能更好,方法是在每个列上使用CONCAT()
,其中包含一个安全的列分隔符(例如,双管||
)作为参数,而不是在利用XML的子查询中使用它。HASHBYTES()
它本身有时容易受到规模上的性能问题的影响。所指出的。如果这是您的瓶颈,您可以尝试在计算列或索引视图(它是确定性的)中实现函数的结果,或者使用另一种方法,如链接post中提到的CLR。https://dba.stackexchange.com/questions/312246
复制相似问题