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

是否需要正确的加入?

sql
  •  10
  • user12861  · 技术社区  · 17 年前

    是否存在任何需要右联接的查询,或者可以始终使用左联接重新编写它们?

    更具体地说,如果没有正确的连接(我猜是隐式的,没有任何子查询或其他狂热),如何重新编写这个连接?

    
    SELECT *
    FROM t1
    LEFT JOIN t2 ON t1.k2 = t2.k2
    RIGHT JOIN t3 ON t3.k3 = t2.k3
    
    7 回复  |  直到 7 年前
        1
  •  11
  •   charles bretana    17 年前

    您始终只能使用左联接…

    SELECT * FROM t1
        LEFT JOIN t2 ON t1.k2 = t2.k2
        RIGHT JOIN t3 ON t3.k3 = t2.k3
    

    等同于:

    Select * From t3 
       Left Join (t1 Left Join t2 
                      On t2.k2 = t1.k2)
          On T2.k3 = T3.K3
    

    一般来说,我总是尽量只使用左联接,因为左联接中左侧的表是其行都包含在输出中的表,我喜欢将它(左侧)视为我正在对其执行cartesion积(join)的“基”集…所以我喜欢先把它放在SQL中…

        2
  •  22
  •   community wiki 8 revs Joel Coehoorn    17 年前

    您总是可以重新编写它们以获得相同的结果集。但是,有时执行计划可能在重要方面(性能)有所不同,有时是正确的连接,让我们用更合理的方式表达查询。

    让我来说明性能差异。程序员倾向于用同时发生的SQL语句来思考。然而,保持一个复杂查询的心理模型在一系列步骤中发生是很有用的,在这些步骤中,表通常按列出的顺序联接。所以您可能有这样的查询:

    SELECT * /* example: don't care what's returned */
    FROM LargeTable L
    LEFT JOIN MediumTable M ON M.L_ID=L.ID
    LEFT JOIN SmallTable S ON S.M_ID=M.ID
    WHERE ...
    

    服务器通常会通过将它所能做的任何事情从WHERE子句应用到列出的第一个表(在本例中是largetable)来启动,以减少它需要加载到内存中的内容。然后它将连接下一个表(mediumtable),然后连接下一个表(smalltable),依此类推。

    我们要做的是使用一种策略,该策略考虑到每个联接表对结果的预期影响。通常,您希望尽可能长时间保持结果集尽可能小。将这个原则应用到上面的示例查询中,我们发现它明显比需要的慢很多。它从较大的集合(表格)开始,向下工作。我们要从较小的组开始,然后开始工作。这意味着首先使用smalltable,而实现这一点的方法是通过右联接。

    这里的另一个关键点是,在连接完成之前,服务器通常不知道需要smalltable中的哪些行。因此,只有当smalltable比large table小得多,将整个smalltable加载到内存中比从large table开始要便宜得多(large table是一个大表,可能索引得很好,可能在一个字段或where子句中过滤了三个字段)。

    同样重要的是要指出,在绝大多数情况下,优化器都会以最有效的方式来看待这一点,并且在大多数情况下,优化器在这方面做得比您所能做的更好。

    但优化器并不完美。有时您需要帮助它:特别是如果一个或多个“表”是一个视图(可能是链接服务器!)或者嵌套的select语句。嵌套的子查询也是一个很好的例子,在这种情况下,出于表达性的原因,您可能希望使用正确的联接:它允许您移动查询的嵌套部分,以便更好地对事物进行分组。

        3
  •  8
  •   Cœur Gustavo Armenta    7 年前

    对!总是!(必须承认,通常在严格要求先打电话给哪个桌子时使用)

    关于这个主题: here's a nice visual guide on joins .

        4
  •  6
  •   David Grant    17 年前

    这有点像问是否使用比以往任何时候都需要的更多。使用一个更适合手头任务的工具。

        5
  •  1
  •   Bill the Lizard    17 年前

    您始终可以交换表顺序以将右联接转换为左联接。有时候这样或那样做效率更高。

        6
  •  -1
  •   Cade Roux    17 年前

    我用 LEFT JOIN S大约99.999%的时间,但我的一些动态代码生成使用 RIGHT JOIN 也就是说,联接之外的内容不需要反转。

    我还想补充一点,您给出的具体示例我相信会产生交叉连接,这可能不是您的意图,甚至不是一个好的设计。

    也就是说,我认为它实际上与:

    SELECT *
    FROM t1
    CROSS JOIN t3
    LEFT JOIN t2
        ON t1.k2 = t2.k2
        AND t3.k3 = t2.k3
    

    而且,由于它是一个交叉连接,优化器将无法完成很多工作。

        7
  •  -2
  •   yfeldblum    17 年前

    许多编程语言中有许多元素,它们不是严格要求达到正确的结果,而是允许一个a)更清楚地表达意图b)以提高性能。示例包括数字、字符、循环、开关、类、联接、类型、筛选器和数千个以上。