优化数据库有啥更好的方法:使用带有不同过滤器的一堆存储过程,还是使用带有 if 条件的单个存储过程?
Posted
技术标签:
【中文标题】优化数据库有啥更好的方法:使用带有不同过滤器的一堆存储过程,还是使用带有 if 条件的单个存储过程?【英文标题】:What's better to optimize a database: use a bunch of stored procedures with different filters or use a single one with if conditions?优化数据库有什么更好的方法:使用带有不同过滤器的一堆存储过程,还是使用带有 if 条件的单个存储过程? 【发布时间】:2021-06-09 19:06:27 【问题描述】:我正在尝试优化我的数据库,所以我决定更改一个存储过程,它有很多“IF 条件”来过滤不同的参数。
所以,我正在考虑更改它并制作一堆具有不同过滤器的存储过程,并停止使用带有很多“IF 条件”的存储过程
只需在我的后端验证使用哪个存储过程,而不是在 SQL Server 中进行验证。
这是最好的方法还是有更好的方法?
我的实际存储过程示例:
CREATE PROCEDURE [dbo].[sp_GetFilters]
@Id INT,
@Name VARCHAR(50),
@LastName VARCHAR(50),
@Age INT,
@AND_MORE_PARAMETERS VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
IF @ID IS NOT NULL AND
@NAME IS NULL AND
@LASTNAME IS NULL AND
@AGE IS NULL AND
@AND_MORE_PARAMETERS IS NULL
BEGIN
SELECT *
FROM EXAMPLE_TABLE
WHERE ID = @ID
END
ELSE IF @ID IS NULL AND
@NAME IS NOT NULL AND
@LASTNAME IS NULL AND
@AGE IS NULL AND
@AND_MORE_PARAMETERS IS NULL
BEGIN
SELECT *
FROM EXAMPLE_TABLE WHERE
NAME = @NAME
END
...
等等..
我想将其更改为一堆不同的存储过程,每个存储过程都有一个唯一的过滤器
这是个好主意吗?有没有更好的方法来优化这个存储过程?
谢谢你的帮助!
【问题讨论】:
单独的过程会更好,但更难维护(尽管很多if/else
也很难维护)。您可能想查看有关Kitchen Sink Queries 的文章,研究安全 动态SQL 和OPTION (RECOMPILE)
提示
在您的具体示例中,我怀疑您会发现最好的折衷方案是将 if/else 逻辑与您的实际查询分开。将每个选择查询移动到自己的过程中,并传递正确的参数;这将确保每个查询都有自己专用的缓存执行计划,并且可以单独重新编译。
不要戳睡熊。如果你改变它,你就拥有它,你要对任何改变导致的事情负责。如果你没有解决问题,那就找点别的事情去做。任何人都不应该更改工作代码,无论它看起来多么有益。
@Stu 执行计划在语句(加上@@options)级别缓存,因此给定示例中的每个 select 语句都有一个单独的计划。也就是说,您可以轻松地sp_recompile N'someStoredProcedure'
,而删除单个语句的计划更加困难,因此按照您的建议使用单独的存储过程是有好处的。
旁注:您应该不为您的存储过程使用sp_
前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_
并使用其他东西作为前缀 - 或者根本不使用前缀!
【参考方案1】:
您可以尝试一个查询,在 WHERE 子句中使用参数评估。我已广泛使用这种方法并取得了巨大成功。
CREATE PROCEDURE dbo.sp_GetFilters
@Id INT = NULL
,@Name VARCHAR(50) = NULL
,@LastName VARCHAR(50) = NULL
,@Age INT = NULL
,@AND_MORE_PARAMETERS VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM EXAMPLE_TABLE
WHERE 1 = 1
AND CASE WHEN @Id IS NULL THEN 1 ELSE ID END = CASE WHEN @Id IS NULL THEN 1 ELSE @Id END
AND CASE WHEN @Name IS NULL THEN '1' ELSE NAME END = CASE WHEN @Name IS NULL THEN '1' ELSE @Name END
AND CASE WHEN @Age IS NULL THEN 1 ELSE AGE END = CASE WHEN @Age IS NULL THEN 1 ELSE @Age END;
/* and so on....*/
END;
【讨论】:
虽然这会起作用,但如果您在定义中的AS
之前添加 WITH RECOMPILE
,效果会更好。否则它经常会使用不合适的执行计划。 Read this.以上是关于优化数据库有啥更好的方法:使用带有不同过滤器的一堆存储过程,还是使用带有 if 条件的单个存储过程?的主要内容,如果未能解决你的问题,请参考以下文章