从头学SQL(四):SQL的执行顺序

引用

关于sql和MySQL的语句执行顺序(必看!!!)
sql语句执行顺序
MySql执行顺序及执行计划
建议看原文

SQL的执行顺序

1.from
2.join
3.on
4.where
5.group by
6.avg,sum…(SQL函数)
7.having
8.select
9.distinct
10.order by

从这个顺序中我们不难发现,所有的查询语句都是从from开始执行的,在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入。

(1) SELECT (2)DISTINCT<select_list>
(3) FROM <left_table>
(4) <join_type> JOIN <right_table>
(5)         ON <join_condition>
(6) WHERE <where_condition>
(7) GROUP BY <group_by_list>
(8) WITH {CUBE|ROLLUP}
(9) HAVING <having_condition>
(10) ORDER BY <order_by_condition>
(11) LIMIT <limit_number>

第一步:对FROM子句中的左表<left_table>右表<right_table> 执行笛卡儿积,产生虚拟表VT1;

第二步:接下来便是应用ON筛选器,ON中的逻辑表达式将应用到 vt1 中的各个行,筛选出满足on逻辑表达式(<join_condition>)的行,生成虚拟表 VT2

第三步:如果是OUTER JOIN 那么这一步就将添加外部行,(left outer jion 就把左表在第二步中过滤的添加进来,如果是right outer join 那么就将右表在第二步中过滤掉的行添加进来)这样生成虚拟表 VT3 。如果FROM子句中的表数目多于两个表,那么就将VT3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表VT3

第四步:应用WHERE筛选器,对上一步生产的虚拟表引用WHERE筛选器,生成虚拟表VT4

在这有个比较重要的细节不得不说一下,对于包含outer join子句的查询,就有一个让人感到困惑的问题,到底在on筛选器,还是用where筛选器指定逻辑表达式呢?
on和where的最大区别在于,如果在on应用逻辑表达式那么在第三步outer join中还可以把移除的行再次添加回来,而where的移除的最终的。

举个简单的例子

有一个学生表(班级,姓名)和一个成绩表(姓名,成绩),我现在需要返回一个x班级的全体同学的成绩,但是这个班级有几个学生缺考,也就是说在成绩表中没有记录。
为了得到我们预期的结果我们就需要在on子句指定学生和成绩表的关系(学生.姓名=成绩.姓名)那么我们是否发现在执行第二步的时候,对于没有参加考试的学生记录就不会出现在vt2中,因为他们被on的逻辑表达式过滤掉了,但是我们用left outer join就可以把左表(学生)中没有参加考试的学生找回来,因为我们想返回的是x班级的所有学生,如果在on中应用学生.班级='x’的话,left outer join会把x班级的所有学生记录找回,所以只能在where筛选器中应用学生.班级=‘x’ 因为它的过滤是最终的

第五步:根据GROUP BY子句中的列(<group_by_list>),对VT4中的记录进行分组操作,产生VT5。如果应用了group by,那么后面的所有步骤都只能得到的VT5的列或者是聚合函数(count、sum、avg等)。原因在于最终的结果集中每个组只包含一行。 这一点请牢记。

第六步:应用cube或者rollup选项,为VT5生成超组,生成VT6.

第七步:应用HAVING筛选器,生成VT7

HAVING筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。

第八步:处理SELECT子句。将VT7中的在SELECT中出现的列筛选出来。生成VT8.

第九步:应用DISTINCT子句,VT8中移除相同的行,生成VT9

事实上如果应用了GROUP BY子句那么DISTINCT是多余的。
原因同样在于,分组的时候是将列中唯一的值分成一组同时只为每一组返回一行记录,那么所以的记录都将是不相同的

第十步:应用ORDER BY子句。按照order_by_condition排序VT9,此时返回的一个游标,而不是虚拟表。sql是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。

对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。 正因为返回值是游标,那么使用order by 子句查询不能应用于表达式。排序是很需要成本的,除非你必须要排序,否则最好不要指定order by.

最后,在这一步中是第一个也是唯一一个可以使用select列表中别名的步骤。

第十一步:LIMIT: 取出指定行的记录,产生虚拟表VT10,并返回给查询用户

开始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->SELECT子句->ORDER BY子句->LIMIT子句->最终结果

实例

select 考生姓名, max(总成绩) as max总成绩   
from tb_Grade     
where 考生姓名 is not null     
group by 考生姓名     
having max(max总成绩) > 600     
order by max总成绩   

在上面的示例中 SQL 语句的执行顺序如下:

  1. 首先执行 FROM 子句, 从 tb_Grade 表组装数据源的数据
  2. 执行 WHERE 子句, 筛选 tb_Grade 表中所有数据不为 NULL 的数据
  3. 执行 GROUP BY 子句, 把 tb_Grade 表按 "学生姓名"列进行分组(注:这一步开始才可以使用select中的别名,他返回的是一个游标,而不是一个表,所以在where中不可以使用select中的别名,而having却可以使用)
  4. 计算 max() 聚集函数, 按 “总成绩” 求出总成绩中最大的一些数值
  5. 执行 HAVING 子句, 筛选课程的总成绩大于 600 分的
  6. 执行SELECT子句,选择考生姓名和max总成绩两列作为最终结果集
  7. 执行 ORDER BY 子句, 把最后的结果按 “max总成绩” 进行排序.

执行计划

1、什么是执行计划

执行计划就是sql的执行查询的顺序,以及如何使用索引查询,返回的结果集的行数

2、执行计划的内容

在这里插入图片描述

①.id sql执行计划的顺序 或子查询表的执行顺序

id一样,按照顺序执行;id越大,执行的优先级就越高(如子查询)

②.select_type 表示查询中每个select子句的类型

在这里插入图片描述

a.SIMPLE:查询中不包含子查询或者UNION

b.查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY

c.在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY

d.在FROM列表中包含的子查询被标记为:DERIVED(衍生)

e.若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在 FROM子句的子查询中,外层SELECT将被标记为:DERIVED

f.从UNION表获取结果的SELECT被标记为:UNION RESULT

③.type

MySQL在表中找到所需行的方式,又称“访问类型”,常见类型如下:

在这里插入图片描述

由左至右,由最差到最好

ALL:全表扫描

index:index类型只遍历索引树

索引的存在形式是文件,按存储结构划分):FULLTEXT,HASH,BTREE,RTREE。

对应存储引擎支持如下
在这里插入图片描述

range:索引范围扫描

对索引字段进行范围查询,使用in则是使用rang范围查询; 使用">" ,"<" 或者 “between” 都是可以使用索引的,但是要控制查询的时间范围,一般查询数据不要超过数据总数的 15%

ref:非唯一性索引

类似 select count(1) from age = ‘20’;

eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描

④.key

表示在执行语句用到的索引

查询中若使用了覆盖索引,则该索引仅出现在key列表中

覆盖索引:查询数据只需要通过索引就可以查询出,如55万条数据,使用索引,立刻可以查询出 2000条数据,同时Extra字段是Using index

⑤.Extra

Using index : 使用覆盖索引的时候就会出现

using index condition:查找使用了索引,但是需要回表查询数据

Using where :在查找使用索引的情况下,需要回表去查询所需的数据

using index & using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据

Using temporary:需要使用临时表来存储结果集,常见于排序和分组查询

Using filesort:无法利用索引完成的排序操作称为“文件排序”;

很多场景都是索引是一个字段,order by 排序的字段与索引字段不一致,导致的Using fileSort;
此时可以给排序字段和where条件字段,添加为组合索引,同时保证索引查询的数据不超过总量的15%,避免fileSort

注:回表的含义是,先根据索引查询数据,然后在根据确定的数据id和查询条件再去查询具体的数据的过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值