What is better, dynamic SQL or where case?

半腔热情 提交于 2019-12-07 18:49:55

问题


I need to create a stored procedure which takes 12 arguments and the query is filtered with a different combination of this arguments. All 12 arguments are not mandatory as if I pass 3 or 5 or 12 arguments depends on search inputs entered by user.

I can create 2 ways, either using a dynamic SQL query or using 'Case where' statements. Example of these queries are as below:

  1. Dynamic Query

    DECLARE @sql VARCHAR(MAX) 
    DECLARE @condition VARCHAR(MAX)=''
    Declare @var1 varchar(10)
    Declare @var2 varchar(10)
    Declare @var3 varchar(10) 
    SET  @sql='SELECT * FROM TableDemo1 TD1 WITH(NOLOCK)
     INNER JOIN TableDemo2 TD2 ON TD1.Column1=TD2.Column2'
    if(@var1 <>0 and @var1 is not null)
    begin
        if(@condition<>'')
        begin
            set @condition=@condition + ' and TD1.columnTest1='+@var1)
        end
        else
        begin
            set @condition=' where TD1.columnTest1='+@var1
        end
    end
    if(@var2 <>0 and @var2 is not null)
    begin
        if(@condition<>'')
        begin
            set @condition=@condition + ' and TD2.columnTest2='+@var2)
        end
        else
        begin
            set @condition=' where TD2.columnTest2='+@var2
        end
    end
    
    if(@var3 <>0 and @var3 is not null)
    begin
        if(@condition<>'')
        begin
            set @condition=@condition + ' and TD1.columnTest3='+@var3)
        end
        else
        begin
            set @condition=' where TD1.columnTest3='+@var3
        end
    end
    SET @sql=@sql+@condition
    EXEC(@sql)
    
  2. Query with CASE WHERE

    Declare @var1 varchar(10)
    Declare @var2 varchar(10)
    Declare @var3 varchar(10)
    SELECT *
    FROM TableDemo1 TD1 WITH(NOLOCK)
        INNER JOIN TableDemo2 TD2 ON TD1.Column1=TD2.Column2
    WHERE
      (CASE WHEN   
        (@var1<>0 and @var1 is not null)   
        THEN  
        CASE WHEN TD1.columnTest1=@var1 THEN 1 ELSE 0 END  
        ELSE 1 END)=1  
      AND   
      (CASE WHEN  
        (@var2<>0 and @var2 is not null)   
        THEN  
        CASE WHEN TD2.columnTest2=@var2 THEN 1 ELSE 0 END  
        ELSE 1 END)=1  
      AND
      (CASE WHEN
        (@var3<>0 AND @var3 IS NOT NULL)
        THEN
        CASE WHEN TD1.columnTest3 = @var3
        THEN 1 ELSE 0 END
        ELSE 1 END) =1
    

This is just part of my stored procedure, there are 7-8 tables with joins and as above in query variety in conditions.

If I use a dynamic query, SQL Server will have to create an execution plan every time, but if I use 'case where' it also makes the query slow.

I am aware of disadvantages of dynamic SQL, but which technique I should use?


回答1:


Generally it depends, but most often I use dynamic queries as a last resort. Regarding your question, I would most probably go with the CASE solution, but I think your CASE expressions are unnecessarily complicated. I would replace the WHERE clause with something like this:

...
WHERE
    TD1.columnTest1 = COALESCE(NULLIF(@var1, 0), TD1.columnTest1)
    AND   
    TD2.columnTest2 = COALESCE(NULLIF(@var2, 0), TD2.columnTest2)
    AND   
    TD1.columnTest3 = COALESCE(NULLIF(@var3, 0), TD1.columnTest3)

With proper indexing this shouldn't be too slow.




回答2:


The dynamic query will lead to an index scan.

The case will lead to a seq scan (i.e. read the whole table).

So definitely go with the dynamic query.




回答3:


In my experience a dynamic where clause provides better performance. Especially over large datasets.

And a very good explanation is in Catch All Queries.




回答4:


I have used the option "Andriy M" posted using coalesce and nullif functions.

But this option works only with the '=' operator, yet to find how to use it with other conditions, one example is using the 'IN' keyword.

TD1.columnTest1 = (
    CASE 
        WHEN (
            ( TD1.columnTest1 
                IN (
                    SELECT item FROM dbo.Splitfunction(@comaSepValues,',')
                )
            ) 
            OR 
            NULLIF(@PlaceTypeCode,'') IS NULL 
        ) THEN columnTest1
        ELSE NULL 
    END
)

Let me know if this works or not.




回答5:


There are two ways to execute dynamic query 1. Exec 2. sp_executeSQL

if you want to reuse your execution plan, then go for sp_executeSQL option.

'SP_ExecuteSQL' accepts parameters, so you can directly pass your parameter to this query which will intern reuse your execution plan.

Dynamic queries are not always in bad performance specially when you are using it appropriately



来源:https://stackoverflow.com/questions/6016475/what-is-better-dynamic-sql-or-where-case

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!