SQL Server是否足够智能,以便在不需要时不执行IO?

时间:2011-09-02 17:18:27

标签: sql-server sql-server-2008 merge sql-server-2008-r2

假设我有一个看起来像这样的合并语句:

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多行和大量索引的合并语句,那么重新更新表中的所有数据将会变得昂贵。

我是否需要首先检查数据是否已更改(至少在性能可能有问题的情况下)?

如果是这样,我如何在合并声明中这样做(可能使用上面的例子)?

2 个答案:

答案 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期间,内存中的数据会定期写入磁盘。