mysql的使用过成中,SELECT的使用是非常频繁的,那么理解SELECT的查询操作就显得非常重要。
对于查询处理,可将其分为逻辑查询处理和物理查询处理。逻辑查询处理表示执行查询应该产生什么样的结果,而物理查询代表mysql数据库是如何得到该结果的。两种查询的方法可能完全不同,但是得到的结果是相同的。
1.逻辑查询处理
SQL的逻辑查询处理的顺序如下:
(7) SELECT
(8) DISTINCT
(1) FROM
(3) JOIN
(2) ON
(4) WHERE
(5) GROUP BY
(6) HAVING
(9) ORDER BY
(10) LIMIT
我们老具体分析查询处理的各个阶段:
FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
ON: 对虚表VT1进行ON筛选,只有那些符合的行才会被记录在虚表VT2中。
JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,一直到处理完所有的表为止。
WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合的记录才会被插入到虚拟表VT4中。
GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
HAVING: 对虚拟表VT6应用having过滤,只有符合的记录才会被 插入到虚拟表VT7中。
SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
ORDER BY: 将虚拟表VT9中的记录按照进行排序操作,产生虚拟表VT10.
LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。
2.物理查询处理
虽然SQL的逻辑查询是根据上述进行查询,但是数据库也许并不会完全按照逻辑查询处理的方式来进行查询。MYSQL数据库有两个组件Parser(分析SQL语句)和Optimizer(优化)。
从官方手册上看,可以理解为,MySQL采用了基于开销的优化器,以确定处理查询的最解方式,也就是说执行查询之前,都会先选择一条自以为最优的方案,然后执行这个方案来获取结果。在很多情况下,MySQL能够计算最佳的可能查询计划,但在某些情况下,MySQL没有关于数据的足够信息,或者是提供太多的相关数据信息,估测就不那么友好了。
1.本人认为解析器解析后的执行顺序是有写变化,首先讨论没有创建索引的情况,having和group by的顺序应该在select之后:
FROM clause
WHERE clause
SELECT clause
GROUP BY clause
HAVING clause
ORDER BY clause
为什么这样说呢,因为mysql中允许在having和group by语句中使用别名(alias),但where语句中是不能直接使用select语句中的别名的,我们来看一个例子:
mysql> select * from formatting;
+---------+------------+-------+--------+-----+
| orderid | orderdate | empid | custid | qty |
+---------+------------+-------+--------+-----+
| 1 | 2010-01-02 | 3 | A | 10 |
| 2 | 2010-04-02 | 2 | B | 20 |
| 3 | 2010-05-02 | 1 | A | 30 |
| 4 | 2010-07-02 | 3 | D | 40 |
| 5 | 2011-01-02 | 4 | A | 20 |
| 6 | 2011-01-02 | 3 | B | 30 |
| 7 | 2011-01-02 | 1 | C | 40 |
| 8 | 2009-01-02 | 2 | A | 10 |
| 9 | 2009-01-02 | 3 | B | 20 |
+---------+------------+-------+--------+-----+
9 rows in set (0.00 sec)
在where中使用别名,数据库返回error说找不到where中的id列,说明数据库还没有解析select。
mysql> select custid as id,count(orderid) as cnt from formatting where id='A';
ERROR 1054 (42S22): Unknown column 'id' in 'where clause'
但是在group by和having中使用别名mysql可以成功解析。
mysql> select custid as id,count(orderid) as cnt from formatting group by id having cnt>2;
+----+-----+
| id | cnt |
+----+-----+
| A | 4 |
| B | 3 |
+----+-----+
2 rows in set (0.00 sec)
2.存在索引的情况下,优化器优先使用条件用到索引且最优的方案,通过例子来看。
当sql条件有多个索引可以选择,且存在索引能唯一定位结果时,mysql优化器将直接使用效率最高的索引执行。
当结果是某个集合时,mysql优化器将使用merge索引的方式提高查询效率,并且虽然我的where顺序是更少数值的在后面,但mysql优化器会自动修正顺序,先查找empid的索引。
从这里可以看出索引的建立对于sql的优化是有一定关键作用的。但不是所有的优化器使用的都是最优的方式,可以具体方案具体分析。
网友评论