Mysql 中各个条件的执行顺序的处理情况。
下面是一段MySQL 查询语句代码:
SELECT DISTINCT <字段列表> FROM <左表> <连接方式> JOIN <右表> ON <连接条件> WHERE <过滤条件> GROUP BY <分组字段> HAVING <包含条件> ORDER BY <排序方式> LIMIT <限制行数>[, <偏移行数>]
以上的伪代码,有联结、过滤、分组、排序等,基本覆盖了查询语句的所有子句。
然而在SQL中,处理的第一个子句是FROM子句,而SELECT在SQL查询中首先出现的子句将在以后进行处理。
SQL查询的逻辑处理涉及的阶段如下:
FORM 子句
ON 条款
OUTER 子句
WHERE 子句
GROUP BY 子句
HAVING 子句
SELECT 子句
DISTINCT 子句
ORDER BY 子句
LIMIT 条款
SQL在查询各个阶级分别干了什么?
(1)Form 阶段
FROM阶段标识出查询的来源表,并处理表运算符。在涉及到联接运算的查询中(各种join),
主要有以下几个步骤:
求笛卡尔积。不论是什么类型的联接运算,首先都是执行交叉连接(cross join),求笛卡儿积,生成虚拟表 VT1-J1。
ON 筛选器。这个阶段对上个步骤生成的 VT1-J1 进行筛选,根据 ON 子句中出现的“谓词”进行筛选,让“谓词”取值为 true 的行通过了考验,插入到 VT1-J2。
添加外部行。如果指定了outer join,还需要将 VT1-J2 中没有找到匹配的行,作为外部行添加到 VT1-J2 中,生成 VT1-J3。
经过以上步骤,FROM 阶段就完成了。概括地讲,FROM 阶段就是进行预处理的,根据提供的运算符对语句中提到的各个表进行处理(除了join,还有 apply,pivot,unpivot)
(2)Where 阶段
Where 阶段是根据 <where_predicate> 中条件对 VT1 中的行进行筛选,让条件成立的行才会插入到 VT2 中。
(3)Group By 阶段
Group 阶段按照指定的列名列表,将 VT2 中的行进行分组,生成 VT3 。最后每个分组只有一行。
(4)Having 阶段
该阶段根据 Having 子句中出现的谓词对 VT3 的分组进行筛选,并将符合条件的组插入到 VT4 中。
(5)Select 阶段
这个阶段是投影的过程,处理 select 子句提到的元素,产生 VT5。这个步骤一般按下列顺序进行:
计算 SELECT 列表中的表达式,生成 VT5-1。
若有 DISTINCT,则删除 VT5-1 中的重复行,生成 VT5-2
若有 TOP,则根据 ORDER BY 子句定义的逻辑顺序,从 VT5-2 中选择签名指定数量或者百分比的行,生成 VT5-3
(6)Order By 阶段
根据 ORDER BY 子句中指定的列明列表,对 VT5-3 中的行,进行排序,生成游标 VC6 。
提示和注意事项:
SELECT先前步骤不能使用列表中创建的别名。强制执行此限制是因为在SELECT评估子句之前出现的子句(例如WHERE子句)时,可能尚未确定列值。
在某些数据库(例如MySQL)中,使用和子句中SELECT允许使用列表中创建的别名,即使这些子句出现在子句之前(并且在其之前评估)。GROUP BYHAVINGSELECT
表达式别名不能被同一SELECT列表中的其他表达式使用。这是因为评估表达式的逻辑顺序无关紧要,并且无法保证。例如,此SELECT子句可能无法按预期工作,因此不受支持:SELECT a + 1 AS x, x + 1 AS y
使用 ON 时INNER JOIN,如果在WHERE子句或ON子句中指定逻辑表达式,则无关紧要。这是正确的,因为ON和之间没有逻辑差异WHERE(除了使用OUTER JOIN或GROUP BY ALL选项时)。
使用时该DISTINCT子句是多余的GROUP BY。因此,它不会从记录集中删除任何行。
ON条件与Where条件的区别
由上述SQL查询执行的顺序可以看出,假设使用左连接(left join)时,
on条件是在生成临时表(VT1)时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
where条件是在临时表(VT1)生成好后,再对临时表进行过滤的条件,进而生成临时表(VT2)。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。
on条件不是最终过滤, 因为后面left join还可能添加回来, 而where才是最终过滤.只有当使用外连接(left, right)时, on 和 where 才有这个区别, 如果用inner join, 在哪里制定都一样, 因为on 之后就是where, 中间没有其它步骤。
总结一下:
在多表联接查询时,on比where更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。
转载地址:http://www.mzh.ren/mysql-query-clause-execution-order.html