您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

如果在插入,更新,删除之前存在以进行优化

如果在插入,更新,删除之前存在以进行优化

我不太确定,但是我得到的印象是,这个问题实际上是关于upsert的,它是以下原子操作:

开发人员转变为DBA常常天真地逐行编写它,如下所示:

-- For each row in source
IF EXISTS(<target_expression>)
    IF @delete_flag = 1
        DELETE <target_expression>
    ELSE
        UPDATE target
        SET <target_columns> = <source_values>
        WHERE <target_expression>
ELSE
    INSERT target (<target_columns>)
    VALUES (<source_values>)

由于以下几个原因,这几乎是您可以做的最坏的事情:

它具有比赛条件。该行可以在IF EXISTS和之后的DELETE或之间消失UPDATE

这很浪费。对于每笔交易,您都需要执行额外的操作;也许是微不足道的,但这完全取决于您的索引编制得如何。

最糟糕的是-它遵循的是迭代模型,在单行级别上考虑这些问题。这将对整体性能产生最大(最坏)的影响。

一个非常小的(我强调一点)的优化是UPDATE无论如何都要尝试。如果该行不存在,@@ROWCOUNT将为0,然后您可以“安全地”插入:

-- For each row in source
BEGIN TRAN

UPDATE target
SET <target_columns> = <source_values>
WHERE <target_expression>

IF (@@ROWCOUNT = 0)
    INSERT target (<target_columns>)
    VALUES (<source_values>)

COMMIT

最坏的情况是,这仍将为每个事务执行两项操作,但至少有 机会 仅执行一项操作,而且还消除了竞争条件(这种情况)。

但是真正的问题是,仍然需要对源代码中的每一行执行此操作。

sql Server 2008之前,您必须使用笨拙的三阶段模型在设置级别上处理此问题(仍然优于逐行):

BEGIN TRAN

INSERT target (<target_columns>)
SELECT <source_columns> FROM source s
WHERE s.id NOT IN (SELECT id FROM target)

UPDATE t SET <target_columns> = <source_columns>
FROM target t
INNER JOIN source s ON t.d = s.id

DELETE t
FROM target t
WHERE t.id NOT IN (SELECT id FROM source)

COMMIT

就像我说的那样,性能还很差劲,但是仍然比单行一次的方法好很多。但是,sql Server 2008最终引入了MERGE语法,因此现在您所要做的就是:

MERGE target
USING source ON target.id = source.id
WHEN MATCHED THEN UPDATE <target_columns> = <source_columns>
WHEN NOT MATCHED THEN INSERT (<target_columns>) VALUES (<source_columns>)
WHEN NOT MATCHED BY SOURCE THEN DELETE;

而已。一个声明。如果您使用的是sql Server 2008,并且需要执行的任何顺序INSERTUPDATE并且DELETE取决于该行是否已经存在- ,则 理由不使用它MERGE

如果您需要随后查找完成的操作,甚至可以OUTPUT将受a影响的行MERGE放入表变量中。简单,快速且无风险。做吧

其他 2022/1/1 18:48:42 有427人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶