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

在检查一个表的pk=另一个表的fk时,所有类型的联接都会减少为内部联接,这是真的吗?

sql
  •  2
  • umar  · 技术社区  · 15 年前

    无论使用哪种类型的联接,如果WHERE子句检查一个表的pk=另一个表的fk,那么只要结果集是连接的,它就会变成与内部联接相同的联接,这是真的吗?换句话说,如果sql查询包含以下内容:

    “从(…)E上的左连接B中选择…,在(A.pk=G.fk)上选择F完全外部连接G,其中A.pk=G.fk和A.pk=B.fk等…”

    在上面的查询中,A左连接到B,而G在其fk上外部连接到A。但是由于where子句有两个检查,因此整个查询简化为如下内容:

    “从(…)E上的内部联接B中选择…,从(…)E上的内部联接G中选择…(A.pk=G.fk)

    询问此查询的原因是,我有许多笛卡尔类型的联接,以及位于一个表的pk=另一个表的fk上的where子句,它们会减慢查询速度。我在考虑用左连接替换笛卡尔积,同时保留所有where子句,或者所有内部连接。

    3 回复  |  直到 15 年前
        1
  •  3
  •   Eric    15 年前

    是的,这是获得内部联接的一种迂回方式。

    想想它是如何工作的:它从A中提取所有内容,然后是匹配的B或null,然后是所有G(A/B和G侧的null),然后它基本上过滤掉所有有null侧的内容(WHERE子句)。所以,是的,内部连接可能更快。

    这种混淆的一个常见原因是:

    SELECT * FROM a INNER JOIN b ON a.id = b.id AND b.something = 'awesome'
    

    相当于:

    SELECT * FROM a INNER JOIN b ON a.id = b.id WHERE b.something = 'awesome'
    

    但是,这种相同的传递方法不适用于完整/外部联接,因为它将进行联接,然后进行过滤(当然,这取决于过滤器和优化器)。

    因此,简而言之:如果您确实想要内部联接,请使用内部联接。

    编辑:我还应该注意,这不是PK/FK交易,而是如果您在WHERE子句中基本上重复ON子句,则完整/外部联接将等效于内部联接。

        2
  •  1
  •   Charles Bretana    15 年前

    是的,您也可以简单地添加

    "Where PK Is Not Null" or 
    "Where FK Is Not Null" 
    

    这也会从连接的“外部”过滤掉“额外”记录。。。

        3
  •  1
  •   HLGEM    15 年前

    是,如果在where子句中引用了除“where myfield为null”之外的任何内容的左外部联接的右侧,则已创建内部联接。这是因为它会过滤掉任何不符合该条件的内容,包括所有与初始表不匹配的记录。与其他非内部联接相同。为了绕过它,你把条件放在连接中。示例(这会将其转换为内部联接):

    Select field1, field2 from mytable mt
    left join mytable2 mt2 on mt.id = m2.id
    where mt1.field1 = 'hello' and mt2.field2 = 'test'
    

    Select field1, field2 from mytable mt
    left join mytable2 mt2 on mt.id = m2.id and mt2.field2 = 'test'
    where mt1.field1 = 'hello' 
    

    “从(A.id=B.A_id)、C、D、F上的内部联接B中选择…,其中A.id=F.id” to:“从上的内部联接B(A.id=B.A\U id)中选择…A.id=F.A\U id上的内部联接F”

    您不希望像这样组合语法;这变得很难维持。事实上,我建议永远不要使用老式的逗号语法,因为它会受到意外交叉连接的影响。因此,在您的示例中,我将编写以获取您当前获得的结果集(至少维护人员会知道您取消了交叉连接,而不是意外地进行交叉连接):

    Select ... From A 
    INNER JOIN B on A.id = B.a_id 
    INNER JOIN F on A.id = F.a_id
    CROSS JOIN C
    CROSS JOIN D
    

    或者,如果交叉连接是偶然的,则代码将更改为:

    Select ... From A 
    INNER JOIN B on A.id = B.a_id
    INNER JOIN F on A.id = F.a_id
    INNER JOIN C on (fill in the join fields)
    INNER JOIN D on (fill in the join fields)