服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Mysql - 关于join on和where执行顺序分析

关于join on和where执行顺序分析

2023-03-06 17:06波波仔86 Mysql

这篇文章主要介绍了join on和where执行顺序,如果是inner join, 放on和放where产生的结果一样, 执行计划也是一样,但推荐使用on,本文对join on和where执行顺序给大家详细讲解,需要的朋友可以参考下

join on和where执行顺序

1、join中相比where优先推荐on

WHERE子句中使用的连接语句,在数据库语言中,被称为隐性连接。INNER JOIN……ON子句产生的连接称为显性连接。(其他JOIN参数也是显性连接)WHERE和INNER JOIN产生的连接关系,没有本质区别,结果也一样。但是!隐性连接随着数据库语言的规范和发展,已经逐渐被淘汰,比较新的数据库语言基本上已经抛弃了隐性连接,全部采用显性连接了。

2. 逻辑上一个query的执行顺序(不是实际) 

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 
说是“逻辑上” 顺序,因为实际执行时还要看索引,数据分布等,看最终优化器如何处理,最真实的顺序肯定是执行计划展示的顺序。

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生效在后,而且on对于outer join有不生效的情况,需要看and条件是作用在左表还是右表。

扩展:SQL执行顺序join在where前面

  • 取a表和b表join的数据sql

原本意图是取a表的昨日分区数据和b表的昨日分区数据进行join,但是发现加上and b.dt = '${daily}'的条件后就取不到在a表中存在的数据了

select substr(a.create_time,1,7) create_month,a.service_id,a.unit_number,a.company_name,coalesce(b.unified_social_credit_code,"unknown") unified_social_credit_code
,a.company_id,b.company_id as company_id_b,a.dt,b.dt
from clouduser.dz_company a 
left join clouduser.dz_company_detail b on a.company_id = b.company_id
where a.dt = "${daily}" 
--and b.dt = "${daily}"
and substr(a.create_time,1,7) = "2022-09"
and a.company_name = "浙江港都电子有限公司";

运行结果

关于join on和where执行顺序分析

  • 原因是where执行是在join之后,join出来的临时表中,由于在b表中没有匹配到数据,所以b.dt为null,这时候执行where b.dt = '${daily}'的条件筛选不到这条数据。
  • 优化方法

现在子查询中将b表的昨日分区查询出来,再和a表join

with
r1 as (select * from clouduser.dz_company_detail where dt = "2022-10-17"),
r2 as (
select substr(a.create_time,1,7) create_month,a.service_id,a.unit_number,a.company_name,coalesce(b.unified_social_credit_code,"unknown") unified_social_credit_code
,a.company_id,b.company_id as company_id_b
from clouduser.dz_company a 
left join r1 b on a.company_id = b.company_id
where a.dt = "${daily}" 
--and b.dt = "${daily}"
and substr(a.create_time,1,7) = "2022-09"
and a.company_name = "浙江港都电子有限公司"
)
select * from r2;

执行结果

关于join on和where执行顺序分析

可以看到正常查询出a表中的数据了

到此这篇关于join on和where执行顺序的文章就介绍到这了,更多相关join on和where执行顺序内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文地址:https://blog.csdn.net/bobozai86/article/details/86689054

延伸 · 阅读

精彩推荐
  • MysqlCentos 5.2下安装多个mysql数据库配置详解

    Centos 5.2下安装多个mysql数据库配置详解

    在实际应用中,有时候,我们需要在同一台服务器上安装两个甚至多个mysql数据库,那么,如何来操作呢,今天我们就来探讨下这个问题 ...

    hebedich1842020-04-07
  • Mysqlmysql 查看版本的方法图文演示

    mysql 查看版本的方法图文演示

    今天打算升级下mysql数据库,可不知道现在的版本是多少,从网上找了一些资料,发现还是这些好用。 ...

    mysql教程网4002019-11-07
  • MysqlMySQL数据库之联合查询 union

    MySQL数据库之联合查询 union

    这篇文章主要介绍了MySQL数据库之联合查询 union,联合查询就是将多个查询结果的结果集合并到一起,字段数不变,多个查询结果的记录数合并,下文详细...

    彭世瑜10412022-11-03
  • Mysql详解MySQL8.0 密码过期策略

    详解MySQL8.0 密码过期策略

    这篇文章主要介绍了MySQL8.0 密码过期策略的相关资料,帮助大家更好的理解和使用MySQL8.0的新功能,感兴趣的朋友可以了解下...

    AsiaYe10642021-03-02
  • Mysqlmysql数据库迁移至Oracle数据库

    mysql数据库迁移至Oracle数据库

    这篇文章主要为大家详细介绍了mysql数据库迁移至Oracle数据库的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    javaee_sunny5342020-06-28
  • MysqlSUSE Linux下通过RPM方式卸载MySQL 5过程笔记

    SUSE Linux下通过RPM方式卸载MySQL 5过程笔记

    这篇文章主要介绍了SUSE Linux下通过RPM方式卸载MySQL 5过程笔记,本文针对使用rpm方式安装的mysql,需要的朋友可以参考下 ...

    MYSQL教程网5432020-04-20
  • Mysqlmysql导出导入中文表解决方法

    mysql导出导入中文表解决方法

    在开发过程中会经常用到mysql导出导入中文表,本文将详细介绍其如何使用,需要的朋友可以参考下 ...

    MYSQL教程网4312019-12-12
  • Mysqlmysql 8.0.15 版本安装教程 连接Navicat.list

    mysql 8.0.15 版本安装教程 连接Navicat.list

    这篇文章主要为大家详细介绍了mysql 8.0.15 版本安装教程,连接Navicat.list,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    小 月5292020-12-01