Mysql关键字执行顺序-深入解析

这篇具有很好参考价值的文章主要介绍了Mysql关键字执行顺序-深入解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


mysql关键字执行顺序如下:
from
on/using
join
where
group by
having
select
distinct
union
order by
limit

一、解释关键字执行顺序

这些关键字涉及的sql笔者这里就不一一去写了。
Mysql会先执行from,然后根据on关键字去筛选目标表,筛选出的结果再进行join或者using,这样就会形成一个临时表。然后去执行where条件去筛选这个临时表,这样基本就筛选出需要的数据了。然后就可以对数据进行group by进行分组,同时若是有必要就会再执行having对数据进行进一步筛选,这里执行完数据基本就是一定定型了,下面就需要select去筛选目标列了,完事之后需要使用distinct进行去重这样一个表的查询基本就结束了。若是需要多表查询则还需要使用union或者union all来进行连接多表的结果。然后就是对数据进行排序的order by ,排完顺序自然就是取分页了。这样就会将一个完整的sql执行完毕了。

二、关于执行顺序可能会有的疑问

对于上面这个执行顺序,都是无需置疑的,不过对于为什么是这样一个顺序笔者曾经也是困惑过的,下面笔者总结了一下可能会产生困惑点,这里列下。

1 on和join 为什么先执行on

我最开始一直认为没有使用join形成一个临时表,那是如何对数据使用on进行条件筛选呢一直不太明白。后来才知道其实在使用left join 或者 right join 时临时表的主体数据本来就是确定的,比如使用left join 那么主表就是左表,那主表已经确定了,所以可以先执行on条件去筛选另一个表的数据,筛选完成后再将两个结果拼接形成一个临时表,mysql这么做就说的通了。rigint join 与left join类似,这里就不重复说了。
上面是用left join 说的例子。那cross join 与 inner join 好像都是会形成笛卡尔积的(mysql5.5以后已经不会有全表的笛卡尔积了)。所以若是两个表在inner join执行前是不知道临时表的数据的,那怎么来使用on条件进行筛选呢?这种情况就不对了啊。所以根据这个点很多人可能会认为应该限制性join 再执行on,其实则不然。

对于inner join 和 cross join 在他们后面使用on条件时,mysql都会将on后面的条件优化到where里,也就是说其实mysql在执行cross join 或者 inner join 时是不会有 on的,这里写on其实写的就是where。所以说cross join 和 inner join 里不存在on语句的,自然就没有先用on条件筛选的场景了。使用 inner join 或者 corss join 无论在on里写什么条件都会被翻译成where语句。所以到这里应该就会明白mysql先执行on关键字再执行 join 关键字是没有问题的了。
下面展示下inner join on 被优化前后的sql对比。
原始sql:

select a.user_id from sys_user  a 
inner join sys_user_role  b on a.user_id = b.user_id; 

被执行优化器优化后的sql(mysql真正执行的语句):

select `sunacwy_cockpit`.`a`.`user_id` AS `user_id` from `sunacwy_cockpit`.`sys_user` `a` 
join `sunacwy_cockpit`.`sys_user_role` `b` where (`sunacwy_cockpit`.`a`.`user_id` = `sunacwy_cockpit`.`b`.`user_id`)

通过上面的例子,就可以验证上面笔者说的内容了。有兴趣的同学可以在测试下非等值连接,自然连接等其他场景。

2 on和where 有什么区别,哪些场景是相同的

当on使用在left join 和 right join 后面时,会对连接数据先进行筛选,然后才会把符合on条件的数据进行连接。连接完成后才会执行where后面的筛选条件。
当on使用在cross join 和 inner join 后面时,就不一样了。此时on和where效果一致,因为这里的on会被sql执行优化器,优化成where,所以这里的on和where是相同的。这一点上面的例子中已经证明了,这里就不重复写了。

3 where和having 的区别

where 和 having在一定程度上可以做一些相同的事,那他们有什么不同呢,其实having最主要的目的是用来执行分组后的聚合函数的,因为where关键字在group by之前执行,所以没法在where后面使用聚合函数,所以才有了having关键字。当然having关键字不仅可以执行聚合函数,同时也可以做与where一样的条件筛选。不过这里需要说明的事,若是非聚合函数的筛选条件一般不要出现在having里,这样会影响sql性能,这种数据筛选一般在where阶段就应该过滤掉,而不应该是执行到having了再去过滤这部分数据。

三、关键字对于sql优化的启示

我们知道更多的数据在越早的阶段被过滤掉越好,sql性能也越高。所以根据这一原则,我们根据sql关键字的执行顺序可以总结出这么一句话:

1.能写在on里的条件,不要写在where里,能写在where里的条件不写在having里

这个很好理解根据各个关键字的执行顺序,很容易就可以看出来先执行on再执行where最后执行haing,所以条件越靠前月有利于sql的执行。不过这里还是需要区分场景的,我们可以从内连和外连两个角度分析这个问题。
1)内连时
内连时,我们写的on条件其实都会解析成where条件,所以我们将条件写在on或者where里是没有区别的,所以此时是on=where>having的关系。
2)外连时
外连时,我们无论以哪个表为基表,那么都是对基表进行全表扫描,所以外连里的on并不会对数据筛选,只有where才会对连接的结果进行筛选,那此时的on其实起不到数据过滤的作用,只有where和having才有过滤数据的作用。
3)总结来说,on起到的过滤作用只是在外连时过滤被连接的表有些作用,因为在内连里本质上没有on,外连时on其实不会过滤基表,只过滤了被连接的表。所以若是必须使用外连时,我们需要尽可能过滤被连接表,然后在where里加筛选条件即可。若是非必要使用外连,建议还是使用内连,因为内连不会全表扫描。

2.使用inner join 或者cross join 、left join 、right join、子查询 怎么选择

先建设一个场景有两个表我们需要关联查询,条件固定(详见下面的sql),需要建立的索引均已建立

数据量
tb_mdm_floor 397364
tb_mdm_unit 53290

①如果我们使用inner join,我们可能会像下面这么写:

select fl.* from tb_mdm_floor fl 
inner join tb_mdm_unit un on fl.unit_id = un.id 
where un.id in (
'16611347838871536931',
'16611347838881537131',
'16611386992314864604',
'16611386992304864504',
'16611386992294864404'
);

②如果我们使用left join,我们可能会像下面这么写:

select fl.* from tb_mdm_floor fl
left join  tb_mdm_unit un on fl.unit_id = un.id  
where un.id in (
'16611347838871536931',
'16611347838881537131',
'16611386992314864604',
'16611386992304864504',
'16611386992294864404'
);

③如果我们使用子查询,我们可能会像下面这么写:

select * from tb_mdm_floor where unit_id in 
(
select id from tb_mdm_unit where id in (
'16611347838871536931',
'16611347838881537131',
'16611386992314864604',
'16611386992304864504',
'16611386992294864404'
));

那这三种查询效率该怎么选择呢,我们分别使用explain看下三种写法扫描的行数就会有感觉了
第①种explaian的分析结果
Mysql关键字执行顺序-深入解析

第②种explaian的分析结果
Mysql关键字执行顺序-深入解析

第③种explaian的分析结果
Mysql关键字执行顺序-深入解析
这样的话效率的高低其实就很简单明了了,我们可以看到使用子查询和内连时数据的扫描行数最少,而使用外连时会扫描基表的所有行数,最后再使用where过滤基表的全部信息。所以我们可以知道需要优先使用内连和子查询。那内连和子查询我们怎么判定优先级呢?若是在mysql5.5以前,肯定是优先使用子查询的,因为mysql5.5以前使用内连会进行全表的笛卡尔积,全表的笛卡尔积是一件很恐怖的事情。但是mysql5.5以后对连接进行了优化,不会再进行全表的笛卡尔积了,使用了一种BNL的算法,进行了优化(未使用索引的情况下,使用索引会使用INL算法)。上面我们使用explain查看的其实是优化后的结果。所以暂时来看子查询与内连效率上没什么差别,但是理论上子查询会更好些。所以我们可以这么总结:子查询 > 内连 > 外连

3.关于连表查询时的笛卡尔的说明

首先我们需要明确的是mysql5.5以后,sql在执行的时候基本是不会做全表的笛卡尔积的,最多都是局部进行笛卡尔积。无论是inner、left、right等都有可能产生笛卡尔积。但现在肯定不会有全表的笛卡尔积了。关于为什么连表查没有全表的笛卡尔积,以及局部又是如何进行优化计算的,请看下这篇文章,这位道友写的还是很通俗易懂的:https://blog.csdn.net/qq_36330228/article/details/125168628文章来源地址https://www.toymoban.com/news/detail-421004.html

到了这里,关于Mysql关键字执行顺序-深入解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • mysql中的关键字

    MySQL是一种流行的开源关系型数据库管理系统,包含许多,这些在MySQL中具有特殊的含义,用于执行各种数据库操作。以下是MySQL中的一些及其用法: ADD:用于向现有表添加一列或多列。 ALTER:用于修改表的结构,例如更改列名、更改列的数据类型、修改索

    2024年02月16日
    浏览(26)
  • MySQL中的COLLATE关键字

    Collation in MySQL refers to the set of rules used to compare and sort characters in a particular character set. It determines how strings are compared and ordered based on their characters’ linguistic and cultural rules. Collation settings affect operations such as sorting, searching, and comparing strings in MySQL queries. In MySQL, collation can be spec

    2024年02月12日
    浏览(24)
  • 谈谈mysql中的各个关键字

    mysql是当今最主流且 开放源码 的 关系型数据库 ,开发者为瑞典 MySQL AB 公司。目前 MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了 MySQL 作为网站数据库

    2024年04月24日
    浏览(25)
  • mysql常见的需求,对于关键字的使用

    如何使用MySQL将列数据转化为逗号分隔的形式。我们可以使用内置函数GROUP_CONCAT()来实现这个功能,也可以根据实际需求自定义一个函数。这种技术在一些需要对数据进行汇总或者展示的场景中非常有用。 SELECT GROUP_CONCAT(x.ancestor) as ancestor FROM ce_module_user.sys_dept_relation x WHERE d

    2024年01月18日
    浏览(63)
  • 软件测试|MySQL DISTINCT关键字过滤重复数据

    简介 在MySQL中,有时候我们需要从表中检索唯一的、不重复的数据。这时,我们可以使用 DISTINCT 来过滤掉重复的数据行。在本文中,我们将深入探讨MySQL中 DISTINCT 的用法以及如何在查询中使用它来得到不重复的结果集。 基本语法 DISTINCT 用于在 SELECT 语句中指示

    2024年02月02日
    浏览(32)
  • MySQL having关键字详解、与where的区别

    1.1、作用 对查询的数据进行筛选 1.2、having产生的原因 使用where对查询的数据进行筛选时,where子句中无法使用聚合函数,所以引出having 1.3、having使用语法 having单独使用(不与group by一起使用,在Oracle中会报错),单独使用时,大部分场合与where相同 having与grou

    2023年04月21日
    浏览(29)
  • 【示例】MySQL-事务控制示例:账户转账-savepoint关键字

    本文讲述MySQL中的事务,以账户转账为例,体会事务的概念,并讲解事务相关的一个用法:savepoint 所有SQL正常执行,没有出错。结果就是:张三账户余额-1000;李四账户余额+1000 只有前两个SQL执行了,第三个SQL没有执行,出现数据不一致了:张三的钱减少了,但是李四

    2024年04月13日
    浏览(24)
  • MySQL中这些关键字的用法,佬们get到了嘛

    前言: 最近粉丝问了一个问题,是关于Limit分页的用法,他没有理解清楚,因此本篇文章主要讲解 MySQL的 的知识。该专栏比较适合刚入坑Java的小白以及准备秋招的大佬阅读。 如果文章有什么需要改进的地方欢迎大佬提出,对大佬有帮助希望可以支持下哦~ 小威在此先

    2024年02月12日
    浏览(29)
  • MySQL索引3——Explain关键字和索引优化(SQL提示、索引失效、索引使用规则)

    目录 Explain 索引性能分析 Id ——select的查询序列号 Select_type——select查询的类型 Table——表名称 Type——select的连接类型 Possible_key ——显示可能应用在这张表的索引 Key——实际用到的索引 Key_len——实际索引使用到的字节数 Ref    ——索引命中的列或常量 Rows——预

    2024年02月14日
    浏览(40)
  • MySQL索引3——Explain关键字和索引使用规则(SQL提示、索引失效、最左前缀法则)

    目录 Explain 索引性能分析 Id ——select的查询序列号 Select_type——select查询的类型 Table——表名称 Type——select的连接类型 Possible_key ——显示可能应用在这张表的索引 Key——实际用到的索引 Key_len——实际索引使用到的字节数 Ref    ——索引命中的列或常量 Rows——预

    2024年02月14日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包