存储过程中的可选 WHERE IN

Optional WHERE IN in stored procedure

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

实现此目标的最佳方法是什么?

  1. 我应该创建三个独立的存储过程吗?这会使存储过程更难管理,因为我必须使三个存储过程保持最新,而不是一个。但是,如果这能让我获得最佳性能,我不介意使用三个存储过程而不是一个。但这真的是性能方面的最佳选择吗?三个独立的存储过程意味着三个独立的查询计划,对吗?

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

  3. 我能想到的最后一个解决方案是使用 table 值参数。条件看起来像这样:WHERE @IdTable IS NULL OR [Id] IN (SELECT [Id] FROM @IdTable)。这个解决方案也比第一个更易于管理,它也避免了 EXEC 的使用。但是,我忍不住觉得这会表现得最差,即使这是唯一会导致一个一致的查询计划的解决方案。这个中的 WHERE 条件比其他的要复杂得多。

您必须在高可维护代码高性能之间做出选择。

编写可维护性高的代码时检查执行计划。

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
)

如果您看到执行计划,table 扫描发生在 @IdTable 上,占总执行成本的 25%。当然,您可以使用带有 Id 索引的“#”临时 table 来删除它,但这仍然是查询的开销。

当您需要像下面这样的高性能查询时。

UPDATE Test
SET LastUpdated = GETDATE()

I suggest you go with a single update, it should work fine if your ID column is Indexed. SQL Server is optimized and capable of handling huge volumes of records.