存储过程中的可选 WHERE IN
Optional WHERE IN in stored procedure
我需要一个存储过程来更新我的 table 之一,它有数百万条记录。为了简单起见,假设它只执行 SET LastUpdated = GETUTCDATE()
。存储过程应该能够以最佳性能执行以下操作。
- 更新所有记录(无
WHERE
)
- 更新 1 条记录(
WHERE [Id] = @Id
)
- 更新 n 条记录 (
WHERE [Id] IN (@IdCsv)
)
实现此目标的最佳方法是什么?
我应该创建三个独立的存储过程吗?这会使存储过程更难管理,因为我必须使三个存储过程保持最新,而不是一个。但是,如果这能让我获得最佳性能,我不介意使用三个存储过程而不是一个。但这真的是性能方面的最佳选择吗?三个独立的存储过程意味着三个独立的查询计划,对吗?
我还可以将所有内容放在一个包含 ID 的 nvarchar
参数的存储过程中,以逗号分隔。然后,结合 EXEC
我可以这样做:
WHERE [Id] IN (' + @IdCsv + ')
。如果@IdCsv 为空,我可以通过省略 where 语句来进一步改进这一点。此解决方案更易于管理,但性能好吗?
我能想到的最后一个解决方案是使用 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.
我需要一个存储过程来更新我的 table 之一,它有数百万条记录。为了简单起见,假设它只执行 SET LastUpdated = GETUTCDATE()
。存储过程应该能够以最佳性能执行以下操作。
- 更新所有记录(无
WHERE
) - 更新 1 条记录(
WHERE [Id] = @Id
) - 更新 n 条记录 (
WHERE [Id] IN (@IdCsv)
)
实现此目标的最佳方法是什么?
我应该创建三个独立的存储过程吗?这会使存储过程更难管理,因为我必须使三个存储过程保持最新,而不是一个。但是,如果这能让我获得最佳性能,我不介意使用三个存储过程而不是一个。但这真的是性能方面的最佳选择吗?三个独立的存储过程意味着三个独立的查询计划,对吗?
我还可以将所有内容放在一个包含 ID 的
nvarchar
参数的存储过程中,以逗号分隔。然后,结合EXEC
我可以这样做:
WHERE [Id] IN (' + @IdCsv + ')
。如果@IdCsv 为空,我可以通过省略 where 语句来进一步改进这一点。此解决方案更易于管理,但性能好吗?我能想到的最后一个解决方案是使用 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.