美文网首页mysql程序员
mysql的查询顺序解析

mysql的查询顺序解析

作者: 小灰灰besty | 来源:发表于2017-04-20 11:48 被阅读0次

    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的优化是有一定关键作用的。但不是所有的优化器使用的都是最优的方式,可以具体方案具体分析。

    相关文章

      网友评论

        本文标题:mysql的查询顺序解析

        本文链接:https://www.haomeiwen.com/subject/buehzttx.html