优化数据库有啥更好的方法:使用带有不同过滤器的一堆存储过程,还是使用带有 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 条件的单个存储过程?的主要内容,如果未能解决你的问题,请参考以下文章

有啥方法可以优化这个 mysql 查询?

当类的实例在 js 中需要不同的函数和变量时,有啥更好的方法?

数据量太大,分页查询变慢,有啥优化查询的方法吗

在Java中用轮廓绘制字符串有啥更好的方法吗?

Unity3D性能优化--- 收集整理的一堆

实现 Access 2007“HTML 报告”的更好方法