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

多个字段的左联接返回不匹配的行

  •  1
  • knittl  · 技术社区  · 10 年前

    是否有可能 LEFT JOIN 在多个字段上,是否会为字段选择具有不同值的行?考虑以下查询:

    SELECT A.a aa, A.b ab, B.a ba, B.b bb
    FROM A
    LEFT JOIN B
    ON A.a = B.a
    AND A.b = B.b
    WHERE A.a = :filter
    

    我想在这里 aa ba 两者都等于 :filter 在任何时候(除非涉及空值)。

    我目前遇到了一个问题,我的结果中出现了我没有预料到的行,我必须将条件放入 WHERE 条款我仍在研究sqlFiddle来重现这个问题。一旦我开始工作,就会链接到它(但也许那时我会自己理解问题)

    改变 左联接 INNER JOIN 也解决了这个问题。但我不明白为什么,我真的想知道背后的逻辑。


    有趣的是,如果我过滤 B.a 为了不为空(有效地将左连接转换为内部连接),我得到了与内部连接相同的预期结果。但如果不进行此检查,我在选定的 B、 一个 领域为什么他们会被过滤 IS NOT NULL 而是用数值显示?Oracle查询优化器是否在做一些可疑的事情?


    添加/*+no_query_transformation*/再次得到正确的结果。

    不同版本的执行计划如下:

    • 原始查询:

      SELECT STATEMENT
        NESTED LOOPS                        OUTER
          TABLE ACCESS            A         BY INDEX ROWID
            INDEX                 A_B_FK    RANGE SCAN
          VIEW PUSHED PREDICATE   B
            FILTER
              TABLE ACCESS        B         BY INDEX ROWID
                INDEX             B_C_FK    RANGE SCAN
      
    • 使用查询 +no_query_transformation :

      SELECT STATEMENT
        VIEW
          NESTED LOOPS                  OUTER
            VIEW               A
              TABLE ACCESS     A        BY INDEX ROWID
                INDEX          A_B_FK   RANGE SCAN
            VIEW
              VIEW             B
                TABLE ACCESS   B        FULL
      
    2 回复  |  直到 10 年前
        1
  •  0
  •   Jens Krogsboell    10 年前

    我会拿我的脖子冒险:

    这是一个Oracle优化器错误,导致优化器在将查询转换为更高效的内容(合并视图等)的过程中错误地解释了查询的意图。

    我们可以说这是一个bug,因为no_query_transform提示将结果更改为预期的结果。除了执行计划之外,我不熟悉任何可能改变任何事情的暗示,当然也不会改变结果。

    这些类型的“错误结果”错误最常见于具有内联性能视图的复杂查询。

        2
  •  0
  •   simon at rcl    10 年前

    这种行为听起来完全是意料之中的:这是LEFT JOIN所做的,通过将其更改为INNER JOIN来修复它就证明了这一点。

    基本上,LEFT JOIN表示(在本例中)从a中返回与WHERE子句匹配的所有行,从b中返回您可以与所选a匹配的所有b,但是如果没有与任何所选a相匹配的b,则无论如何都返回a,其中b中的值为空。

    将其更改为INNER JOIN不会返回没有b的a。同样的效果可以通过在where子句中排除空b列来获得,正如您也注意到的那样。

    这就是LEFT联接的行为方式。