当前位置: 首页 > 面试题库 >

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

洪增
2023-03-14
问题内容

在很多情况下,您需要根据某些条件执行INSERT,UPDATE或DELETE语句。我的问题是,对查询性能的影响是否在命令前添加了IF EXISTS。

例子

IF EXISTS(SELECT 1 FROM Contacs WHERE [Type] = 1)
    UPDATE Contacs SET [Deleted] = 1 WHERE [Type] = 1

INSERT或DELETE呢?


问题答案:

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

  • 如果该行同时存在于源和目标中,UPDATE则为目标。
  • 如果该行仅存在于源中,则INSERT该行进入目标;否则,该行进入目标。
  • (可选)如果该行存在于目标中而 不是 源中,DELETE则来自目标的行。

开发人员转变为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放入表变量中。简单,快速且无风险。做吧



 类似资料:
  • 问题内容: 我有一个带有2个表的数据库,如下所示: 列是,并且是 和 在申请表中,我有2个编辑框,名称分别为和 如果用户像电子邮件一样插入一个新的负责人姓名, 那么在保存表格的过程中,我想将新的负责人姓名插入表中,请插入最后一个并将其更新为。 如果用户保持名称,但它更新电子邮件一样,然后我想在从1 =使用新的电子邮件地址和他们(其余和)保持不变。 如果负责人的名称相同,我想保留from表的原始引用

  • 插入、更新和删除语句基于以开头的层次结构生成 UpdateBase . 这个 Insert 和 Update 构建基于中介的 ValuesBase . DML基础构造函数 顶级的“插入”、“更新”、“删除”构造函数。 Object Name Description delete(table[, whereclause, bind, returning, ...], **dialect_kw) 构建

  • 问题内容: 我想向数据库表中添加一行,但是如果存在具有相同唯一键的行,我想更新该行。 例如: 假设唯一键为,并且在我的 数据库 中有一行。在这种情况下,我想用这些值更新该行。通常,这会产生错误。 如果使用它,将忽略该错误,但仍不会更新。 问题答案: 采用 查询:

  • 我有一个由Access DB使用ResultSet&填充的JTable。我有一个方法可以正确地从数据库中删除记录,但在刷新表模型的当前视图时遇到了困难。我看过类似的帖子,并尝试使用和,但没有成功。我还注意到其他帖子提到了的使用,因为它有add/remove行方法,但我使用的代码来自我去年使用的Java教科书(教授从未达到这一点,所以我试图自己学习)... 以下是定制JFrame的类: 下面是Abs

  • 问题内容: 我正在尝试使用SQLAlchemy模块(而不是SQL!)在python中编写大量upsert。 我在SQLAlchemy添加上遇到以下错误: 我有一个称为列的主键的表。 在此示例中,我已经在数据库中使用了一行。当我尝试将新对象设置为时,出现上述错误。我的印象是,如果主键已经存在,记录将得到更新。 我如何仅基于主键就可以对Flask-SQLAlchemy进行增补? 有没有简单的解决方案?

  • 问题内容: 我在下面有一个SQL插入程序,它工作正常,但是我希望它检查DATE = xxxx,NAME = xxxx和JOB = xxx并更新HOURS(如果它们存在),否则插入新行。SQL可以做到这一点吗? 尝试以下具有相同结果的OR替换,每次都会添加一个新行。 例如: 如果以下内容位于数据库中,并且John要更新其工作时间,它将检查名称,日期,作业是否与尝试插入的值相同,并且它们是否仅更新HO