zoukankan      html  css  js  c++  java
  • 实操-mysql表连接笛卡尔积(join、left join)和select查询执行顺序

    1、为什么两张表连接会出现重复数据

    2、表的连接过程是怎样的?

    举例:

      表A:

        1

        0

      表B:

        1

        0

        0

        2

      执行语句:select * from A join B on A.id = B.id;

      顺序如下:

        join形成的表:

          1 1

          1 0

          1 0

          1 2

          0 1

          0 0

          0 0

          0 2

        on之后:

          1 1

          0 0

          0 0

      所以表连接后出现了重复数据

      

      两张表的关系存在一对多的关系,所以就会出现重复情况


    什么是笛卡尔积呢?
      就是两张表连接的时候,是通过笛卡尔积的方式连接。
      笛卡尔(Descartes)乘积又叫直积。假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以扩展到多个集合的情况。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。
      所以两个表连接后(使用join、逗号连接)就是笛卡尔积。

      无论是join还是left join,都是先把表以笛卡尔积的方式连接,然后通过on来筛选数据,join只显示符合条件的数据,left join不仅会显示所有满足条件的数据,而且还会把主表没有匹配上的也显示出来
      

      


      

      

      left join后面必须加上on

      

    总的来说执行顺序如下

    1、from

    2、有多表关联的情况,先产生笛卡尔积

    3、on,对产生的笛卡尔积进行筛选

    4、join,对on筛选的结果生成一张临时表

    5、如果是out join(left),还需要把没匹配上的行数添加和join的数据合并,生成一张临时表

    6、where,对临时表进行过滤

    7、

    别人好的解释:(1.)select语句的执行顺序


    Processing Order of the SELECT statement
    The following steps show the processing order for a SELECT statement.
    1.FROM
    2.ON
    3.JOIN
    4.WHERE
    5.GROUP BY
    6.WITH CUBE or WITH ROLLUP
    7.HAVING
    8.SELECT
    9.DISTINCT
    10.ORDER BY
    11.TOP
    (5)SELECT DISTINCT
    (7)TOP(<top_specification>) <select_list>
    (1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate>
    (2)WHERE <where_predicate>
    (3)GROUP BY <group_by_specification>
    (4)HAVING <having_predicate>
    (6)ORDER BY <order_by_list>
    T-SQL在查询各个阶级分别干了什么:
    (1)FROM 阶段
    FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种join),主要有以下几个步骤:
    a.求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),求笛卡儿积,生成虚拟表VT1-J1。
    b.ON筛选器。这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。
    c.添加外部行。如果指定了outer join,还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。
    经过以上步骤,FROM阶段就完成了。概括地讲,FROM阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有apply,pivot,unpivot)
    (2)WHERE阶段
    WHERE阶段是根据<where_predicate>中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。
    (3)GROUP BY阶段
    GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。
    (4)HAVING阶段
    该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。
    (5)SELECT阶段
    这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行
    a.计算SELECT列表中的表达式,生成VT5-1。
    b.若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2
    c.若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2中选择签名指定数量或者百分比的行,生成VT5-3
    (6)ORDER BY阶段
    根据ORDER BY子句中指定的列明列表,对VT5-3中的行,进行排序,生成游标VC6.
    如果On和where只能选其一的话:
    先进行on的过滤, 而后才进行join, 这样就避免了两个大表产生全部数据的笛卡尔积的庞大数据.
    这些步骤执行时, 每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入。这些虚拟表对调用者(客户端应用程序或者外部查询)不可用。只是最后一步生成的表才会返回 给调用者。
    如果没有在查询中指定某一子句,将跳过相应的步骤。
    (2) 那 on 和where 那个更高效呢
    如果是inner join, 放on和放where产生的结果一样, 但没说哪个效率速度更高? 如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后.
    综合一下, 感觉还是放在on里更有效率, 因为它先于where执行.
    先笛卡尔积, 然后再on过滤, 如果join是inner的, 就继续往下走, 如果join 是left join, 就把on过滤掉的左主表中的数据再添加回来; 然后再执行where里的过滤;
    on中不是最终过滤, 因为后面left join还可能添加回来, 而where才是最终过滤.
    只有当使用外连接(left, right)时, on 和 where 才有这个区别, 如果用inner join, 在哪里制定都一样, 因为on 之后就是where, 中间没有其它步骤.









          

      

      

    (1.)select语句的执行顺序
    Processing Order of the SELECT statement
    The following steps show the processing order for a SELECT statement.
    1.FROM
    2.ON
    3.JOIN
    4.WHERE
    5.GROUP BY
    6.WITH CUBE or WITH ROLLUP
    7.HAVING
    8.SELECT
    9.DISTINCT
    10.ORDER BY
    11.TOP
    (5)SELECT DISTINCT
    (7)TOP(<top_specification>) <select_list>
    (1)FROM <left_table> <join_type> JOIN <right_table> ON <on_predicate>
    (2)WHERE <where_predicate>
    (3)GROUP BY <group_by_specification>
    (4)HAVING <having_predicate>
    (6)ORDER BY <order_by_list>
    T-SQL在查询各个阶级分别干了什么:
    (1)FROM 阶段
    FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种join),主要有以下几个步骤:
    a.求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),求笛卡儿积,生成虚拟表VT1-J1。
    b.ON筛选器。这个阶段对上个步骤生成的VT1-J1进行筛选,根据ON子句中出现的谓词进行筛选,让谓词取值为true的行通过了考验,插入到VT1-J2。
    c.添加外部行。如果指定了outer join,还需要将VT1-J2中没有找到匹配的行,作为外部行添加到VT1-J2中,生成VT1-J3。
    经过以上步骤,FROM阶段就完成了。概括地讲,FROM阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有apply,pivot,unpivot)
    (2)WHERE阶段
    WHERE阶段是根据<where_predicate>中条件对VT1中的行进行筛选,让条件成立的行才会插入到VT2中。
    (3)GROUP BY阶段
    GROUP阶段按照指定的列名列表,将VT2中的行进行分组,生成VT3。最后每个分组只有一行。
    (4)HAVING阶段
    该阶段根据HAVING子句中出现的谓词对VT3的分组进行筛选,并将符合条件的组插入到VT4中。
    (5)SELECT阶段
    这个阶段是投影的过程,处理SELECT子句提到的元素,产生VT5。这个步骤一般按下列顺序进行
    a.计算SELECT列表中的表达式,生成VT5-1。
    b.若有DISTINCT,则删除VT5-1中的重复行,生成VT5-2
    c.若有TOP,则根据ORDER BY子句定义的逻辑顺序,从VT5-2中选择签名指定数量或者百分比的行,生成VT5-3
    (6)ORDER BY阶段
    根据ORDER BY子句中指定的列明列表,对VT5-3中的行,进行排序,生成游标VC6.
    如果On和where只能选其一的话:
    先进行on的过滤, 而后才进行join, 这样就避免了两个大表产生全部数据的笛卡尔积的庞大数据.
    这些步骤执行时, 每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入。这些虚拟表对调用者(客户端应用程序或者外部查询)不可用。只是最后一步生成的表才会返回 给调用者。
    如果没有在查询中指定某一子句,将跳过相应的步骤。
    (2) 那 on 和where 那个更高效呢
    如果是inner join, 放on和放where产生的结果一样, 但没说哪个效率速度更高? 如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后.
    综合一下, 感觉还是放在on里更有效率, 因为它先于where执行.
    先笛卡尔积, 然后再on过滤, 如果join是inner的, 就继续往下走, 如果join 是left join, 就把on过滤掉的左主表中的数据再添加回来; 然后再执行where里的过滤;
    on中不是最终过滤, 因为后面left join还可能添加回来, 而where才是最终过滤.
    只有当使用外连接(left, right)时, on 和 where 才有这个区别, 如果用inner join, 在哪里制定都一样, 因为on 之后就是where, 中间没有其它步骤.

  • 相关阅读:
    如何使用Doxygen生成keil工程的代码文档 (how to use doxygen properly with keil)
    使用matlab画相交的平面
    转载:关于循环异步操作 Promise 实现,ES7 的 await 和 async
    小众软件:相见恨晚的 Windows 系统下的 cmd 的命令行替代者 Cmder(完美神器)
    Windows系统环境下Python脚本实现全局“划词复制”功能
    Ubuntu shell 命令行路径缩短
    shell查找数组是否有特定的值
    保存数据到文件
    左值与右值
    进程与线程的区别
  • 原文地址:https://www.cnblogs.com/smallpigger/p/8400589.html
Copyright © 2011-2022 走看看