代码之家  ›  专栏  ›  技术社区  ›  richardtallent

SQL查询执行快捷方式或逻辑?

  •  7
  • richardtallent  · 技术社区  · 16 年前

    我有三张桌子:

    SmallTable
       (id int, flag1 bit, flag2 bit)
    JoinTable
       (SmallTableID int, BigTableID int)
    BigTable
       (id int, text1 nvarchar(100), otherstuff...)
    

    SmallTable 最多有几十张唱片。 BigTable 有几百万个,实际上是一个视图,它将此数据库中的一个表与同一服务器上另一个数据库中的一个表结合在一起。

    连接逻辑如下:

    SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE
        (s.flag1=1 OR b.text1 NOT LIKE 'pattern1%')
        AND (s.flag2=1 OR b.text1 <> 'value1')
    

    平均连接大小是几千个结果。显示的所有内容都已编入索引。

    对于大多数 小桌子 记录, flag1 flag2 设置为 1 ,所以实际上甚至不需要访问bigtable.text1上的索引,但无论如何,SQL Server都会这样做,从而导致昂贵的索引扫描和嵌套循环。

    是否有更好的方法向SQL Server提示,如果 FLAG1 标志2 都设置为 不该费心看的 text1 ?

    实际上,如果我能在这些情况下完全避免到bigtable的联接(jointable是托管的,所以这不会产生问题),那么这个键查询就更快了。

    5 回复  |  直到 16 年前
        1
  •  5
  •   JohnFx    16 年前

    SQL布尔值计算执行 不是 保证操作人员短路。见 On SQL Server boolean operator short-circuit 例如,假设操作员短路会导致正确性问题和运行时错误。

    另一方面,我链接中的示例显示了 为SQL Server工作:提供SQL可以使用的访问路径。所以,和 全部的 SQL性能问题和疑问,真正的问题不在于SQL文本的表达方式,而在于存储的设计。也就是说,查询优化器可以使用哪些索引来满足您的查询?

        2
  •  1
  •   AdaTheDev    16 年前

    不幸的是,我不相信SQL Server会出现这样的短路情况。

    所以我建议做两个查询并将它们结合在一起。第一个查询使用s.flag1=1和s.flag2=1 where条件,第二个查询使用s.flag1<>1 a s.flag2<>1条件执行对bigtable的联接。

    This 关于这一问题的文章值得一读,并包括底线:

    …SQL Server不这样做 像短路一样 其他编程语言和 你没办法强迫它 去。

    更新:
    This 本文也是一篇有趣的文章,包含了关于这个主题的一些很好的链接,其中包括与SQL Server查询处理器团队的开发经理的TechNet聊天,该团队简要地提到优化器允许进行短路评估。我从各种文章中得到的总体印象是“是的,优化器可以发现短路的机会,但您不应该依赖它,也不能强迫它”。因此,我认为联合方法可能是你最好的选择。如果它没有想出一个计划,利用一个机会来缩短,这将是基于成本的优化器认为它找到了一个合理的计划,没有做到这一点(这将取决于索引,统计等)。

        3
  •  0
  •   Josh Kodroff    16 年前

    它不优雅,但它应该起作用…

    SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE
        (s.flag1 = 1 and s.flag2 = 1) OR 
        (
           (s.flag1=1 OR b.text1 NOT LIKE 'pattern1%')
           AND (s.flag2=1 OR b.text1 <> 'value1')
        )
    
        4
  •  0
  •   Andomar    16 年前

    SQL Server通常获取子查询提示(尽管可以随意丢弃它):

    SELECT      * 
    FROM        (
                SELECT * FROM SmallTable where flag1 <> 1 or flag2 <> 1
                ) s
    INNER JOIN  JoinTable j ON j.SmallTableID = s.ID
    ...
    
        5
  •  0
  •   Hogan    16 年前

    不知道如果没有测试数据这是否会更快…但听起来可能

    SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE
        (s.flag1=1) AND (s.flag2=1)
     UNION ALL
     SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE
        (s.flag1=0 AND b.text1 NOT LIKE 'pattern1%')
        AND (s.flag2=0 AND b.text1 <> 'value1')
    

    请告诉我发生了什么事

    另外,您可以通过只返回该查询的唯一ID,然后使用该ID的结果获取所有其他数据来加快速度。

    编辑

    像这样?

    SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE
        (s.flag1=1) AND (s.flag2=1)
     UNION ALL
     SELECT * FROM
        SmallTable s
        INNER JOIN JoinTable j ON j.SmallTableID = s.ID
        INNER JOIN BigTable b ON b.ID = j.BigTableID
    WHERE EXISTS
        (SELECT 1 from BigTable b
         WHERE   
        (s.flag1=0 AND b.text1 NOT LIKE 'pattern1%')
        AND (s.flag2=0 AND b.text1 <> 'value1')
    )