从建表到关于sql和MySQL的查询语句执行顺序最新详解

Posted 何义竏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从建表到关于sql和MySQL的查询语句执行顺序最新详解相关的知识,希望对你有一定的参考价值。

SELECT语句关键字的定义顺序

序号为关键字执行顺序:

select distinct  --------- 7777
	...
from  --------- 1111
	...
join  --------- 2222
	...
on  --------- 3333
	...
where  --------- 4444
	...
group by  --------- 5555
	...
having  --------- 6666
	...
order by  --------- 8888
	...
limit  --------- 9999
	...

SELECT语句关键字的执行顺序

  1. from
  2. join
  3. on
  4. where
  5. group by
  6. having
  7. select
  8. distinct
  9. order by
  10. limit

建表和准备数据(DML)

新建测试数据库players

create database players;

通过查找数据库能看到新建的数据库:

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| hyqwsq             |
| information_schema |
| mysql              |
| performance_schema |
| players            |
| sys                |
| testdb             |
+--------------------+
7 rows in set (0.00 sec)

创建测试表 star, ballvalue, starworth

创建表1,设置参数有 球星 (star),球队 (team),上场时间 (time):

CREATE TABLE star (
	star VARCHAR ( 10 ) NOT NULL,
	team VARCHAR ( 10 ) NOT NULL,
	time INT NOT NULL,
	PRIMARY KEY ( star )) ENGINE = INNODB DEFAULT charset = utf8;

创建表2,设置参数有 进球数 (goal),球星 (star),得分 (score):

CREATE TABLE ballvalue (
	goal INT NOT NULL auto_increment,
	star VARCHAR ( 10 ),
	score INT NOT NULL,
	PRIMARY KEY ( goal )) ENGINE = INNODB DEFAULT charset = utf8;

创建表3,设置参数有 上场时间 (time),上场时间等级 (worth):

CREATE TABLE starworth (
	time INT NOT NULL,
	worth INT NOT NULL,
	PRIMARY KEY ( time )) ENGINE = INNODB DEFAULT charset = utf8;

新增测试数据

insert into star(star,team,time) values('James','Lakes',35);
insert into star(star,team,time) value('Kobe','Lakes',40);
insert into star value('alex','bull',10);
insert into star values('Frank','det',16);
insert into star values('Tyler','bull',15);
insert into star values('cory','det',22);
insert into star values('cooper','eagle',28);
insert into star values('hunter','eagle',32);
insert into star values('Gorden','hou',18);
insert into star values('Green','hou',30);

insert into ballvalue value(28,'Kobe',81);
insert into ballvalue value(30,'James',75);
insert into ballvalue value(20,'hunter',45);
insert into ballvalue value(3,'Tyler',9);
insert into ballvalue value(13,'Green',25);
insert into ballvalue value(8,'Frank',18);
insert into ballvalue value(6,'cory',12);
insert into ballvalue value(15,'cooper',30);
insert into ballvalue value(5,'alex',15);
insert into ballvalue value(4,'Gorden',8);

insert into starworth value(10,27);
insert into starworth value(28,60);
insert into starworth value(22,56);
insert into starworth value(16,40);
insert into starworth value(18,48);
insert into starworth value(30,75);
insert into starworth value(32,80);
insert into starworth value(35,95);
insert into starworth value(40,99);
insert into starworth value(15,32);

添加好数据后可以查看表:

mysql> select * from starworth;
+------+-------+
| time | worth |
+------+-------+
|   10 |    27 |
|   15 |    32 |
|   16 |    40 |
|   18 |    48 |
|   22 |    56 |
|   28 |    60 |
|   30 |    75 |
|   32 |    80 |
|   35 |    95 |
|   40 |    99 |
+------+-------+
10 rows in set (0.00 sec)

mysql>  select * from star;
+--------+-------+------+
| star   | team  | time |
+--------+-------+------+
| alex   | bull  |   10 |
| cooper | eagle |   28 |
| cory   | det   |   22 |
| Frank  | det   |   16 |
| Gorden | hou   |   18 |
| Green  | hou   |   30 |
| hunter | eagle |   32 |
| James  | Lakes |   35 |
| Kobe   | Lakes |   40 |
| Tyler  | bull  |   15 |
+--------+-------+------+
10 rows in set (0.00 sec)

mysql> select * from ballvalue;
+------+--------+-------+
| goal | star   | score |
+------+--------+-------+
|    3 | Tyler  |     9 |
|    4 | Gorden |     8 |
|    5 | alex   |    15 |
|    6 | cory   |    12 |
|    8 | Frank  |    18 |
|   13 | Grean  |    25 |
|   15 | cooper |    30 |
|   20 | hunter |    45 |
|   28 | Kobe   |    81 |
|   30 | James  |    75 |
+------+--------+-------+
10 rows in set (0.00 sec)

准备SQL逻辑查询测试语句

写一个查询测试语句:
查询出场时间等级总和大于90的球队中总得分超过60的球队

select
	n.team,
	sum( n.worth ),
	sum( n.time ),
	sum( b.score ) 
from
	(select
		s.star,
		s.team,
		sw.worth,
		sw.time 
	from
		star s
		join starworth sw 
		on s.time = sw.time 
	where
		s.time > 10 
	) n
	join ballvalue b 
	on b.star = n.star 
group by
	n.team 
having
	sum( b.score ) > 60 
order by
	sum( b.score ) desc;

习惯看长句的同学看这里:

mysql> select n.team,sum(n.worth),sum(b.score)
    -> from(select s.star, s.team, sw.worth, sw.time from star s join starworth sw on s.time = sw.time where s.time > 10) n
    -> join ballvalue b on b.star = n.star
    -> group by n.team having sum(b.score) > 60 order by sum(b.score) desc;

执行顺序分析(重点)

在这些SQL语句的执行过程中,每次执行都会产生一个虚拟表,用来保存SQL语句的执行结果(这是重点),跟踪这个虚拟表的变化,就能得到最终的查询结果的过程,用来分析整个SQL逻辑查询的执行顺序和过程。

(1) 执行FROM语句

通过观察最终的查询语句可以发现我写的是嵌套子查询,所以先分析子查询语句:

select
	s.star, s.team, sw.worth, sw.time 
from
	star s
	join starworth sw on s.time = sw.time 
where
	s.time > 10

第一步,执行 from 语句。from 就是告诉你最开始从哪个表开始查询,现在有 star as sstarworth as sw 两个表,而两表连接是通过 笛卡尔积 来连接

所谓笛卡尔积,通俗点说就是指包含两个集合中任意取出两个元素构成的组合的集合

经过 from 语句对两个表执行笛卡尔积,会得到一个虚拟表,先叫XB1 (虚拟表1),内容如下:

mysql> select * from star join starworth;
+--------+-------+------+------+-------+
| star   | team  | time | time | worth |
+--------+-------+------+------+-------+
| Tyler  | bull  |   15 |   10 |    27 |
| Kobe   | Lakes |   40 |   10 |    27 |
| James  | Lakes |   35 |   10 |    27 |
| hunter | eagle |   32 |   10 |    27 |
| Green  | hou   |   30 |   10 |    27 |
| Gorden | hou   |   18 |   10 |    27 |
| Frank  | det   |   16 |   10 |    27 |
...
...中间数据过多,我删了一部分,方便理解就好
...
| hunter | eagle |   32 |   40 |    99 |
| Green  | hou   |   30 |   40 |    99 |
| Gorden | hou   |   18 |   40 |    99 |
| Frank  | det   |   16 |   40 |    99 |
| cory   | det   |   22 |   40 |    99 |
| cooper | eagle |   28 |   40 |    99 |
| alex   | bull  |   10 |   40 |    99 |
+--------+-------+------+------+-------+
100 rows in set (0.00 sec)

总共有100(star 的记录条数 * starworth 的记录条数)条记录。这就是 XB1 的结果,接下来的操作就在 XB1 的基础上进行。


(2) 执行ON过滤

执行完笛卡尔积以后,接着就进行 on s.time = sw.time 条件过滤,根据 on 中指定的条件,去掉那些不符合条件的数据,得到 XB2 表,内容如下:

mysql> select * 
	 > from star s 
	 > join starworth sw 
	 > on s.time = sw.time;
+--------+-------+------+------+-------+
| star   | team  | time | time | worth |
+--------+-------+------+------+-------+
| alex   | bull  |   10 |   10 |    27 |
| cooper | eagle |   28 |   28 |    60 |
| cory   | det   |   22 |   22 |    56 |
| Frank  | det   |   16 |   16 |    40 |
| Gorden | hou   |   18 |   18 |    48 |
| Green  | hou   |   30 |   30 |    75 |
| hunter | eagle |   32 |   32 |    80 |
| James  | Lakes |   35 |   35 |    95 |
| Kobe   | Lakes |   40 |   40 |    99 |
| Tyler  | bull  |   15 |   15 |    32 |
+--------+-------+------+------+-------+
10 rows in set (0.00 sec)

XB2 就是经过 on 条件筛选以后得到的有用数据,而接下来的操作将在 XB2 的基础上继续进行。


(3) 添加外部行

这一步只有在连接类型为 outer join 时才发生,如 left outer join, right outer joinfull outer join。在大多数的时候,我们都是会省略掉 outer 关键字的,但 outer 表示的就是外部行的概念。

相对应的 inner join 就是内连接,而内外链接的区别就是有无主副之分,内连接没有,外连接则有

我创建的数据库的表里没有null值,所以这里用orcle的数据库来测试左外连接和右外连接:

left outer join 把左表记为主表,主表数据都被保留,得到的结果为:

mysql> select * 
	 > from emp e 
	 > left join dept d 
	 > on e.deptno = d.deptno;
+-------+--------+-----------+------+------------+---------+---------+--------+--------+------------+----------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO | DEPTNO | DNAME      | LOC      |
+-------+--------+-----------+------+------------+---------+---------+--------+--------+------------+----------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |     30 | SALES      | CHICAGO  |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |     30 | SALES      | CHICAGO  |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |     30 | SALES      | CHICAGO  |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |     30 | SALES      | CHICAGO  |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |以上是关于从建表到关于sql和MySQL的查询语句执行顺序最新详解的主要内容,如果未能解决你的问题,请参考以下文章

第一次写博,就贡献出这篇MySQL优化经验。

mysql如何查询SQL中哪些语句执行最占用CPU?

关于sql和MySQL的语句执行顺序(必看!!!)

sql查询语句的各个命令执行的标准顺序是啥?为啥?

sql查询语句的各个命令执行的标准顺序是啥?为啥?

关于SQL语句的执行先后顺序,希望高手解答并写出原因。谢谢,