假设我有一个看起来像这样的合并语句:
merge TableA as target
using (select Id, Description, UnitCost
from TableB)
as source (Id, Description, UnitCost)
on (target.Id = source.Id)
when MATCHED then
update set Id = source.Id,
Description = source.Description,
UnitCost = Source.UnitCost
when NOT MATCHED then
insert (Id, Description, UnitCost)
values (source.Id, source.Description, source.UnitCost);
当我运行它时,它告诉我有多少行受到影响。如果我运行它并且我知道源和目标完全相同,我仍然会收到一条消息,告诉我x行数受到影响。在我的情况下,它约200行。 SQL Server是否将相同的数据重写到磁盘?
200行没什么,可以很容易地重写,而不会影响SQL Server的性能。但是如果我有一个包含500,000多行和大量索引的合并语句,那么重新更新表中的所有数据将会变得昂贵。
我是否需要首先检查数据是否已更改(至少在性能可能有问题的情况下)?
如果是这样,我如何在合并声明中这样做(可能使用上面的例子)?
答案 0 :(得分:2)
merge TableA as target
using (select Id, Description, UnitCost
from TableB)
as source (Id, Description, UnitCost)
on (target.Id = source.Id)
when MATCHED AND (ID <> source.ID OR Description <> source.Description OR UnitCost <> Source.UnitCost) then
update set Id = source.Id,
Description = source.Description,
UnitCost = Source.UnitCost
when NOT MATCHED then
insert (Id, Description, UnitCost)
values (source.Id, source.Description, source.UnitCost);
您可以在Matched语句中添加条件搜索子句,这基本上会检查以确保某些内容确实已更改。不确定这是否必然更快,但不会更新不需要更新的行。
如果您需要更多信息,请查看文档MERGE (T-SQL)
答案 1 :(得分:2)
SQL Server,以及任何缓冲池预先写入引擎的事务,都不会为更新/删除/插入执行数据IO。自ARIES论文发表以来,它一直都是这样的,几乎所有的现代关系数据库都将它们的祖先追溯到System-R和ARIES。
当更新行(并且包括插入和删除行)时,日志记录将附加到内存中描述更改的日志缓冲区中,然后更新包含内存中行的页面。没有任何内容写入磁盘。执行继续。当事务提交时,会生成新的日志记录,并且在所有内存中的日志之前无法继续提交,直到并包括日志提交记录都会刷新到磁盘。这是允许更新进行所需的唯一强制IO。如果更新500k行,则在一个语句中,系统将只需等待所有500k行更新后的日志的刷新。
在checkpoints期间,内存中的数据会定期写入磁盘。