【问题标题】:Adding Additional Where Clause in SQL Takes Big Performance Hit在 SQL 中添加额外的 Where 子句会对性能造成很大影响
【发布时间】:2011-01-20 21:04:59
【问题描述】:

我有一个贯穿多个视图和表的 SQL 查询。

查询运行良好,但是当我在 WHERE 子句中添加另一个条件时,它开始对性能产生巨大影响。

查询的结构类似于...

         SELECT a.*
           FROM vw_myView a
LEFT OUTER JOIN tbl1 b ON a.ID = b.ID
LEFT OUTER JOIN vw_OtherView c ON a.ID = c.ID
LEFT OUTER JOIN tbl2 d ON c.OtherID = d.OtherID
          WHERE a.Column1 = 'VALUE'
            AND a.Column2 LIKE ISNULL(@parameter, a.Column2)

从上面的查询中,当我在 WHERE 子句中添加另一个条件时,我的查询现在需要很长时间(超过 3 分钟)来执行并返回 1000 条记录。删除添加的条件子句和查询在不到 7 秒内返回记录。

谢谢。 我应该检查什么以查看性能影响巨大的地方

【问题讨论】:

  • 实际条件是否添加AND a.Column2 LIKE ISNULL(NULL, a.Column2)?因为它不应该为查询添加任何值(dud 子句)
  • @cyberwiki 不仅是一个无用的条款,而且是一个性能打击
  • 编辑了我的答案并提供了一种重写以获得更好性能的方法

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

查看查询的execution plan。我会向甜甜圈打赌,你的额外搜索参数会导致表扫描,这是一个非常昂贵的过程,性能方面。

【讨论】:

    【解决方案2】:

    您的查询子句AND a.Column2 LIKE ISNULL(@parameter, a.Column2) 涉及调用一个函数,因此 SQL Server 必须在您的表中执行 表扫描(即针对 每一 行测试该函数)以看看它是否满足查询。

    即使你在 a.Column2 上有一个索引,Sql Server 也无法使用它。

    [编辑]这是在大多数情况下加快速度的一种方法

    -- Only this part executes when the @parameter has a value.
    -- It returns nothing and executes fast when @parameter is NULL
    
    SELECT a.*
               FROM vw_myView a
    LEFT OUTER JOIN tbl1 b ON a.ID = b.ID
    LEFT OUTER JOIN vw_OtherView c ON a.ID = c.ID
    LEFT OUTER JOIN tbl2 d ON c.OtherID = d.OtherID
              WHERE a.Column1 = 'VALUE'
                AND a.Column2 LIKE @parameter
    
    UNION ALL
    
    -- This part does not execute when the @paramter has a value
    -- This will leave the 2nd query clause out and run faster when @parameter is not specified, avoiding a table scan
    
    SELECT a.*
               FROM vw_myView a
    LEFT OUTER JOIN tbl1 b ON a.ID = b.ID
    LEFT OUTER JOIN vw_OtherView c ON a.ID = c.ID
    LEFT OUTER JOIN tbl2 d ON c.OtherID = d.OtherID
              WHERE a.Column1 = 'VALUE'
                AND @parameter IS NULL
    

    【讨论】:

    • 我使用 NULL 作为测试,但我传递给它一个实际值。虽然有时可能没有传递任何值,所以我必须将参数测试为 NULL。
    • 如果有多个参数传递给查询呢?好像第一个参数是NULL,第二个有值,第三个是NULL等等……?
    • 我会投票给这个答案,因为这实际上符合我的需要。虽然我能够想出结合使用 sp_executesql 的条件 sql 查询。谢谢。
    【解决方案3】:

    动态 SQL 可能是您最好的选择。如果参数为空,则创建一个语句,如果不是,则创建不同的语句。这是使用许多可能的参数加快搜索速度的常用方法。

    既然你只有这两个条件,我可能会尝试这样写: 如果@参数为空

    BEGIN
        SELECT a.*            
        FROM vw_myView a 
        LEFT OUTER JOIN tbl1 b 
        ON a.ID = b.ID 
        LEFT OUTER JOIN vw_OtherView c 
        ON a.ID = c.ID 
        LEFT OUTER JOIN tbl2 d ON c.OtherID = d.OtherID           
        WHERE a.Column1 = 'VALUE'             
        AND a.Column2 LIKE a.Column2 
    END
    ELSE 
    BEGIN
        SELECT a.*            
        FROM vw_myView a 
        LEFT OUTER JOIN tbl1 b 
        ON a.ID = b.ID 
        LEFT OUTER JOIN vw_OtherView c 
        ON a.ID = c.ID 
        LEFT OUTER JOIN tbl2 d ON c.OtherID = d.OtherID           
        WHERE a.Column1 = 'VALUE'             
        AND a.Column2 LIKE  @parameter
    END
    

    当然,你不应该在生产代码中使用 SELECT *,如果可能的话,使用 = 而不是 LIKE。如果这些视图引用相同的表,那么直接查询这些表可能是性能更好的选择。

    【讨论】:

      【解决方案4】:

      试试这个。

      AND (a.Column2 = @parameter OR @parameter is NULL)
      

      不明白为什么要使用like?

      你想做这样的事吗

      AND (a.Column2 like @parameter+'%' OR @parameter is NULL)
      

      【讨论】:

        【解决方案5】:

        为什么要这样做? AND a.Column2 LIKE ISNULL(NULL, a.Column2)
        那总是要检查a.Column2 LIKE a.Column2
        您是否只想检查a.Column2 IS NULL

        您能否按照修改前的状态发布查询?

        [编辑]
        我不知道你的目标数据库,但如果是 Sybase,我会提醒你不要使用@parameter + '%',它会进行表扫描。你可以在To LIKE or not to LIKE阅读更多内容。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-01
          • 2017-03-22
          • 1970-01-01
          • 2013-12-05
          相关资源
          最近更新 更多