- join中相比where优先推荐on
WHERE子句中使用的连接语句,在数据库语言中,被称为隐性连接。INNER JOIN……ON子句产生的连接称为显性连接。(其他JOIN参数也是显性连接)WHERE和INNER JOIN产生的连接关系,没有本质区别,结果也一样。但是!隐性连接随着数据库语言的规范和发展,已经逐渐被淘汰,比较新的数据库语言基本上已经抛弃了隐性连接,全部采用显性连接了。
无论怎么连接,都可以用join子句,但是连接同一个表的时候,注意要定义别名,否则产生错误!
参考:http://blog.sina.com.cn/s/blog_54cd1aa30100plmx.html
- 逻辑上一个query的执行顺序(不是实际)
- FROM
- ON
- JOIN
- WHERE
- GROUP BY
- WITH CUBE or WITH ROLLUP
- HAVING
- SELECT
- DISTINCT
- ORDER BY
- TOP
说是“逻辑上” 顺序,因为实际执行时还要看索引,数据分布等,看最终优化器如何处理,最真实的顺序肯定是执行计划展示的顺序。
下面这段参考: http://www.phpddt.com/db/join-on-where.html
引用
SQL语句中join连表时on和where后都可以跟条件,那么对查询结果集,执行顺序,效率是如何呢?
通过查询资料发现:
区别:
on是对中间结果进行筛选,where是对最终结果筛选。
执行顺序:
先进行on的过滤, 而后才进行join。
效率:
如果是inner join, 放on和放where产生的结果一样, 但没说哪个效率速度更高? 如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后.
最后来了解下T-SQL对查询逻辑处理。
T-SQL逻辑查询的各个阶段(编号代表顺序):
(5)SELECT DISTINCT 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.
如果是inner join, 放on和放where产生的结果一样, 执行计划也是一样,但推荐使用on。但如果有outer join (left or right), 就有区别了, 因为on生效在先, 已经提前过滤了一部分数据, 而where生效在后,而且where对于outer join有不生效的情况:http://www.cnblogs.com/hgwy/articles/1691689.html
参考:
http://www.phpddt.com/db/join-on-where.html
http://dba.stackexchange.com/questions/5038/sql-server-join-where-processing-order
http://blog.chinaunix.net/uid-27570589-id-3771152.html
这篇http://coolshell.cn/articles/3463.html也提到:
引用
如果不是使用嵌套的select语句,一般系统都会产生笛卡尔乘积然再做过滤。这是对于性能来说是非常危险的,尤其是表很大的时候。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/77ad8f8e86aed7c9598f1fe8d6978233.png#pic_center
SQL 语句执行顺序,如下图,共有11个步骤:
具体的每个阶段:
(1) :FORM: 对FROM的前两个表计算笛卡尔积。产生虚表VT1
(2) :ON: 对虚表VT1进行ON筛选,只有那些符合的行才会被记录在虚表VT2中
(3) :JOIN:如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, 如果 from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止(所以,将大数据量的表最后处理性能最好,因为前面处理时虚拟表最小)
(4) :WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合的记录才会被插入到虚拟表VT4中
(5) :GROUP BY: group by 子句将表中的唯一的值组合成为一组,得到虚拟表VT5。如果应用了group by,那么后面的所有步骤都只能得到的vt5的列或者是聚合函数列,原因在于最终的结果集中只为每个组包含一行
(6) :CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
(7) :HAVING: 对虚拟表VT6应用having过滤,只有符合的记录才会被 插入到虚拟表VT7中
(8) :SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中
(9) :DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9(如果应用了group by,那么distinct就是多余的)
(10) :ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10
(11) :LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回