是否存在插入 + 删除比更新更快的实际场景?(SQL 服务器)

use*_*867 5 performance sql-server etl insert parallelism

我只是想知道是否存在插入/删除组合比更新其他插入函数更快的常见场景。

这是我的具体例子。

我必须使用一次包含 1000 条记录的页面更新数据库。(我无法合并页面)。

这些记录中约有 5% 或 50 行是需要“更新”而不是作为全新插入的重复项。

我认为,不是“基于 ID 更新,否则插入新行”的典型功能,“插入所有内容”并在最后一次性删除重复项可能会更快。

两个原因:

  1. 并行性。如果我希望多个进程同时处理这个任务,那么......如果我有一个很大的提交大小和同时搜索和更新 ID 的事务,我可能会遇到行锁。通过“插入所有内容”并稍后删除“旧”记录,我可以有无限的进程同时写入数据。

  2. 我觉得在最后优化一个大的“删除查找”很容易。它看起来像下面这样:

    with CTE as (
       select primary_id,update_date,
              rn = row_number()over(partition by primary_id order by update_date desc)
       from MyTable
    )
    delete from CTE where rn > 1
    
    Run Code Online (Sandbox Code Playgroud)

我的意思是性能提升是存在的——我只是想知道这是否违背了最佳实践。有人能明白为什么插入 + 删除重复项似乎比“更新,如果没有找到,插入”更快?

我可以看到一个危险是在数据加载运行时有一段时间表不准确(在删除之前)。但是在任何更新过程中,这种情况难道不是真的吗?

这也将是数据仓库的临时表,而不是实时使用的数据。我只是想知道为什么我没有经常看到这种方法。

Pau*_*ite 7

在实践中插入和删除比实现相同最终结果的单个更新更快的原因有很多。我什至不打算列出所有注意事项,但例如:

  • 影响索引键的更新可能会从执行计划执行就地更新,但在最低级别并非如此。影响索引键的更新会导致在 SQL Server 2005 以后的存储引擎级别进行单独的删除和插入

  • 更改唯一索引中键值的更新通常意味着 SQL Server 必须在执行计划中引入拆分/排序/折叠组合,以避免暂时违反唯一键。拆分显式地将每次更新转换为单独的删除和插入操作。额外运算符(特别是排序)的成本通常会导致性能降低。向唯一索引插入或删除的计划不需要这种相同的保护,尽管由于其他原因仍可能看到拆分运算符。

  • 有可用于插入的内部优化,这些优化不适用于更新(或删除)。其中一些与最少的日志记录相关,而另一些则需要提示或跟踪标志(如610)。其他优化不需要跟踪标志或提示,并且不会在执行计划中公开。

我的意思是性能提升在那里

这是关键点。我可以告诉你,我的经验是更新和删除在 SQL Server 中通常不如插入优化,但关键是在你的环境中进行测试。插入和删除并不总是比单个更新快,就像单独的操作并不总是比单个操作快一样MERGE(尽管这可能更常见)。

甚至在某些情况下,插入后跟更新(!) 可能比单个更新更快。尽管与您的示例没有直接关系,但您可能会在我的文章“优化更新查询”中找到有关该示例的详细信息。

还相关: