文章目录
- SQL 简介
- SQL 语句的执行顺序
- 重点
SQL 简介
SQL 是 Structured Query Language
的缩写,称为结构化查询语言,SQL 是一种操作关系型数据库的规则,SQL 语句以分号结尾,不区分大小写,建议关键词使用大写。
SQL 语句的执行顺序
(7) SELECT
(8) DISTINCT <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
下面我们来具体分析一下查询处理的每一个阶段:
FORM:
对 FROM
的左边的表和右边的表计算笛卡尔积。产生虚拟表 VT1
。
ON:
对虚拟表 VT1
进行 ON
筛选,只有那些符合 <join-condition>
的行才会被记录在虚拟表 VT2
中。
JOIN:
如果指定了 OUTER JOIN
(比如 left join
、 right join
),那么保留表中未匹配的行就会作为外部行添加到虚拟表 VT2
中,产生虚拟表 VT3
, 如果 from
子句中包含两个以上的表的话,那么就会对上一个 join
连接产生的结果 VT3
和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
WHERE:
对虚拟表 VT3
进行 WHERE
条件过滤。只有符合 <where-condition>
的记录才会被插入到虚拟表 VT4
中。
GROUP BY:
根据 group by
子句中的列,对 VT4
中的记录进行分组操作,产生虚拟表 VT5
。
CUBE | ROLLUP:
对表 VT5
进行 cube
或者 rollup
操作,产生虚拟表 VT6
。
HAVING:
对虚拟表 VT6
应用 having
过滤,只有符合 <having-condition>
的记录才会被 插入到虚拟表 VT7
中。
SELECT:
执行 select
操作,选择指定的列,并对字段进行处理,计算 select
子句中的表达式,产生虚拟表 VT8
。
DISTINCT:
对 VT8
中的记录进行去重。产生虚拟表 VT9
。
ORDER BY:
将虚拟表 VT9
中的记录按照 <order_by_list>
进行排序操作,返回游标 VC10,而不是虚拟表。SQL 是基于集合理论的,集合不会预先对它的行排序,它只是成员的逻辑集合,成员的顺序是无关紧要的。对表进行排序的查询可以返回一个对象,这个对象包含特定的物理顺序的逻辑组织。这个对象就叫游标。正因为返回值是游标,那么使用 ORDER BY 子句查询不能应用于表表达式。排序是很需要成本的,除非你必须要排序,否则最好不要指定 ORDER BY。这一步是第一步也是唯一一步可以使用 SELECT 列表中的列别名的步骤。
LIMIT:
从 VC10
的开始处选择指定数量行,生成虚拟表 VT11
,并将结果返回。
写的顺序:
select ... from... where.... group by... having... order by.. limit...
执行顺序:
from... where...group by... having.... select ... order by... limit...
重点
错误的理解:
select … where,where 子句比 selec 子句先执行,但是数据库是逐行判断的,也就是说数据库在执行 SQL 语句时,指针会移动到表中的第一行,先判断第一行记录是否满足 where 子句的条件,满足则执行 select 子句,将整行记录的所有字段值存储到虚拟表中(注意:如果 select 子句中自定义了其它字段,那么这个步骤会将自定义的字段及相关的字段值存储到虚拟表中)。接着移动指针到下一行,再判断是否满足 where 子句的条件;如果不满足则放弃该条记录,接着指针移到下一行,再判断是否满足 where 子句的条件。重复上述的流程直到无记录可读取为止。
但是最终在返回查询结果时,selec 子句指定了什么字段,返回的结果集中则包含哪些字段。
正确的理解:
先逐行判断记录是否满足 where 子句的条件,不满足则放弃,满足则将整行记录的字段值存储到虚拟表 VT0 中,直到整张表的数据筛选完成后,再执行 select 子句从虚拟表 VT0 中获取指定的列和值到虚拟表 VT1 中,最后将结果返回。
如果 select 子句中含有变量表达式,在执行 where 子句时,有时候这些表达式会同步进行计算,而有的时候不会计算,具体什么情况下会计算,什么情况下不会计算,我也不清楚。但是这里要提醒的是,即便表达式同步计算了,并不表示 select 子句在执行,所以不要以为变量的值发生变化了就认为 where 子句执行完后紧跟着就执行了 select 子句,其实并不是这样的。