存储过程中的可选WHERE IN

时间:2018-02-06 09:55:34

标签: sql-server tsql stored-procedures sql-server-2012 sql-execution-plan

我需要一个存储过程来更新我的一个表,它有数百万条记录。为简单起见,我们假设它只是SET LastUpdated = GETUTCDATE()。存储过程应该能够以最佳性能执行以下操作。

  • 更新所有记录(无WHERE
  • 更新1条记录(WHERE [Id] = @Id
  • 更新 n 记录(WHERE [Id] IN (@IdCsv)

实现这一目标的最佳方式是什么?

  1. 我应该创建三个单独的存储过程吗?这将使存储过程不易管理,因为我必须保持三个存储过程是最新的而不是一个。但是,如果这让我获得最佳性能,我不介意有三个存储过程而不是一个。但这真的是最好的选择,表现明智吗?三个单独的存储过程意味着三个单独的查询计划,对吧?

  2. 我还可以将所有内容放在一个带有nvarchar参数的存储过程中,该参数包含以逗号分隔的ID。然后,结合EXEC我可以这样做:
    WHERE [Id] IN (' + @IdCsv + ')。如果@IdCsv为null,我可以通过省略where语句来进一步改进这一点。这个解决方案更易于管理,但它的表现是否良好?

  3. 我能想到的最后一个解决方案是使用表值参数。条件如下所示:WHERE @IdTable IS NULL OR [Id] IN (SELECT [Id] FROM @IdTable)。此解决方案比第一个解决方案更易于管理,并且还避免使用EXEC。但是,我不禁感到这会导致最糟糕的情况,即使这是唯一可以导致一致的查询计划的解决方案。这个中的WHERE条件比其他条件复杂得多。

1 个答案:

答案 0 :(得分:0)

您必须在高维护代码高性能之间进行选择。

在编写高维护代码时检查执行计划。

DECLARE @ID INT
SET @ID=NULL
DECLARE @IdTable TABLE(ID INT)

UPDATE Test
SET LastUpdated = GETDATE()
WHERE (ID = @ID OR @ID IS NULL)
OR EXISTS
(
 SELECT 1 FROM @IdTable T WHERE T.ID = ID
)

enter image description here

如果您看到执行计划,则会在@IdTable上进行表格扫描,这会占总执行成本的25%。当然你可以通过使用带有Id索引的'#'临时表来删除它,但它仍然是查询的开销。

当您想要高性能查询时,如下所示。

UPDATE Test
SET LastUpdated = GETDATE()

enter image description here

  

我建议您使用单个更新,如果您的ID,它应该可以正常工作   列已索引。 SQL Server已经过优化并且能够处理   大量的记录。