下面这些是从“技术内幕”书中归纳的。
“查询处理可将其分为逻辑查询处理与物理查询处理。前者表示执行查询应该产生怎样的结果,后者表示MYSQL数据库会根据优化器来选择某条路径去得到该结果。”
这里有一个完整的查询语句,且有它们的执行顺序:
(8)SELECT(9) 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)WITH{CUBE|ROLLUP}
(7)HAVING<having_condition>
(10)ORDER_BY<order_by_list>
(11)LIMIT<limit_number>
简单说明一下:SQL语言并不是完全按顺序执行的,第一个执行的是FROM子句,最后是LIMIT操作;在FROM子句中会对左表各右表(如果有)执行笛卡儿积,产生虚拟表VT1;接下来由ON条件进行筛选;另外SELECT选择列操作在每8个步骤执行。
简要说一下在一些步骤中注意的地方:
(1)过滤条件共有三个:ON,WHERE,HAVING
(2)对于OUTER JOIN中的过滤,在ON过滤器过滤完之后还会添加保留表中被ON条件过滤掉的记录,而WHERE 条件中被过滤掉的记录则是永久过滤;在INNER JOIN 中两者没有差别
有这样的SQL语句:SELECT * FROM TABLE1 AS t1 LEFT JOIN TABLE2 AS t2 ON t1.col1=t2.col2AND t1.col3="xx" ;
其中,因为是AND连接了两个过滤条件,所以会对保留表中被排除的记录进行再次的添加操作;如果是用WHERE连接则不会。而要是INNER JOIN 的话,那么就没区别了。
(3)在WHERE子句中由于数据还没进行分组(根据查询语句的顺序),因此现在还不能在WHERE过滤器中使用where_condition=MIN(col)这类对统计的过滤
(4)同样,由于没有进行列的选取操作,因此在WHERE中使用SELECT里的别名也是不被允许的。如:
SELECT userName as name FROM user WHERE name="haha";
[Err] 1054 - Unknown column "name' in 'where clause'
按照那个顺序来看的话,只有在DISTINCT,ORDER_BY中才可能出现SELECT里出现的别名。
(5)子查询不能用做分组的聚合函数,如HAVING COUNT(SELECT ......)<2是不合语法的。
(6)SELECT部分在每8步才执行,列的别名不能在SELECT中的其它别名表达式中使用。如:
SELECT order_id as o,o+1 as n FORM orders;这也是不合语法的。
(7)对于使用了GROUP BY 的查询,再使用DISTINCT是多余的,因为已进行了分组
(8)在MYSQL数据库中,NULL值在升序过程中总是首先被选出,即NULL值在ORDER BY 子句中被视为最小值。
(9)对于大数据的应用来说,LIMIT(m,n)的效率十分低下,应该在应用层建立一定的缓存机制。