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 阶段是根据 中条件对 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进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。