Mysql查询语句的执行顺序

select distinct a
from b left join c
on b.a = c.a
where d = 1
group by e
having avg(f) > 
order by g desc
limit h 3,3

执行顺序
(1)from
(2) on
(3) join
(4) where
(5)group by(开始使用select中的别名,后面的语句中都可以使用)
(6) avg,sum…
(7)having
(8) select
(9) distinct
(10) order by
(11) limit
解释

  1. 首先对from子句中的b和c两个表算笛卡尔积,此时生成虚拟表 vt1。
  2. 应用on筛选器,on 中的逻辑表达式(b.a = c.a)将应用到 vt1 中的各个行,筛选出满足on逻辑表达式的行,生成虚拟表 vt2 。
  3. 接下来执行join,如果是inner join则直接生成虚拟表vt3;如果是outer join 那么这一步就将添加外部行,left outer join 就把左表在第二步中被过滤再加进来,如果是right outer join 那么就将右表在第二步中过滤掉的行再加进来,此时生成虚拟表 vt3 。
  4. 应用where筛选器,对上一步生产的虚拟表vt3应用where筛选器,生成虚拟表vt4。如果要对虚拟表vt4进一步筛选,必须将筛选条件置于where筛选其中,因为置于on筛选器中的话,在执行outer join时会把剔除的行再添加回来,并用null补充。 一言以蔽之,on执行在outer join 之前,where执行在outer join之后,所以on后面只跟表连接条件,具体的筛选还是应该放到where后面。
select s.sno,sc.scgrade from s left join sc on s.sno = sc.sno and scgrade >60;
+-----+---------+
| sno | scgrade |
+-----+---------+
| 1   | 80      |
| 2   | NULL    |
| 3   | 80      |
| 4   | NULL    |
+-----+---------+
4 rows in set (0.00 sec)
select s.sno,sc.scgrade from s left join sc on s.sno = sc.sno where scgrade >60;
+-----+---------+
| sno | scgrade |
+-----+---------+
| 1   | 80      |
| 3   | 80      |
+-----+---------+
2 rows in set (0.00 sec)
  1. group by 子句将中的唯一的值组合成为一组,得到虚拟表vt5。如果应用了group by,那么后面的所有步骤都只能得到的vt5的列或者是聚合函数(count、sum、avg等)。原因在于最终的结果集中只为每个组包含一行。此后可以使用列别名。
  2. 应用having筛选器,生成vt7。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。
  3. 处理select子句。将vt7中的在select中出现的列筛选出来。生成vt8.
  1. 应用distinct子句,vt8中移除相同的行,生成vt9。事实上如果应用了group by子句那么distinct是多余的,原因同样在于,分组的时候是将列中唯一的值分成一组,同时只为每一组返回一行记录,那么所以的记录都将是不相同的。
  2. 应用order by子句。按照order_by_condition排序vt9,此时返回的是一个游标,而不是虚拟表。sql是基于集合的理论的,集合不会预先对他的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使用order by 子句查询不能应用于表表达式。排序是很需要成本的,除非你必须要排序,否则最好不要指定order by,最后,在这一步中是第一个也是唯一一个可以使用select列表中别名的步骤。
    参考来源:https://blog.csdn.net/u014044812/article/details/51004754
  1. 应用limit,返回结果。

猜你喜欢

转载自blog.csdn.net/qq_42962353/article/details/108754020