哪个更快:选择现有行与不存在行的更新?

And*_*ton 5 sql-server-2005 sql-server-2008

哪个会跑得最快?

  1. 使用主键从表中选择(整数、聚集索引、1,000,000+ 行)
  2. 尝试在不同的表上进行更新,其中该行不存在?(整数主键的 where 子句,聚集索引,200,000+ 行)

背景

我们目前有一些程序需要维护其表的过滤副本。

涉及的表:

  • [MasterTable] 包含过滤条件
  • [ChildTable] 被过滤
  • [ChildFilterTable] 保存过滤后的记录

目前正在通过以下方式完成这项工作:

  1. 选择过滤条件
  2. 如果过滤条件匹配,则:
    1. 尝试更新
    2. 如果没有记录更新,插入一条新记录

示例 SQL:

DECLARE @FilterValue INT

/* Get FilterValue to check */
SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable

IF @FilterValue = 123
BEGIN
    /* Attempt update */
    UPDATE [ChildFilterTable] SET
        ...
    WHERE ChildID = @IDFromChildTable

    IF @@ROWCOUNT = 0
    BEGIN
        /* Row not there yet, insert it! */
        INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
    END
END
Run Code Online (Sandbox Code Playgroud)

提议的改变

改成:

  1. 尝试更新
  2. 如果没有记录更新,则:
    1. 选择过滤条件
    2. 如果过滤条件匹配,则:插入新记录

所以:

DECLARE @FilterValue INT

/* Attempt update */
UPDATE [ChildFilterTable] SET
    ...
WHERE ChildID = @IDFromChildTable

IF @@ROWCOUNT = 0
BEGIN
    /* Get FilterValue to check */
    SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable

    IF @FilterValue = 123
    BEGIN
        /* Row not there yet, insert it! */
        INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
    END
END
Run Code Online (Sandbox Code Playgroud)

注意:业务规则确认过滤器值一旦设置就永远不会更改,[MasterTable]因此我们无需担心更新与过滤器记录不匹配的值(即:如果它在 ChildFilterTable 中,我们想要更新它。

gbn*_*gbn 7

不能在一个原子操作中使用SQL Server 2008添加的MERGE语句来“UPSERT”吗?

DECLARE @FilterValue INT

;MERGE 
INTO ChildFilterTable AS CFT
USING  (your filter, source thing here)
                  ON (CFT.ChildID = ...)
WHEN MATCHED
    THEN update stuff
WHEN NOT MATCHED BY TARGET
    THEN insert stuff;
Run Code Online (Sandbox Code Playgroud)