下面我们来具体分析一下查询处理的每一个阶段MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是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, 并将结果返回。

子查询的执行

子查询又称内部查询,而包含子查询的语句称之外部查询(又称主查询)。

所有的子查询可以分为两类,即相关子查询和非相关子查询。

非相关子查询是独立于外部查询的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询。

相关子查询的执行依赖于外部查询的数据,外部查询执行一行,子查询就执行一次。

使用过oracle或者其他关系数据库的DBA或者开发人员都有这样的经验,在子查询上都认为数据库已经做过优化,能够很好的选择驱动表执行,然后在把该经验移植到mysql数据库上,但是不幸的是,mysql在子查询的处理上有可能会让你大失所望,在我们的生产系统上就碰到过一些案例,例如:SELECT i_id,

sum(i_sell) AS i_sell

FROM table_data

WHERE i_id IN

(SELECT i_id

FROM table_data

WHERE Gmt_create >= '2011-10-07 00:00:00')

GROUP BY i_id;

(备注:sql的业务逻辑可以打个比方:先查询出10-07号新卖出的100本书,然后在查询这新卖出的100本书在全年的销量情况)。

这条sql之所以出现的性能问题在于mysql优化器在处理子查询的弱点,mysql优化器在处理子查询的时候,会将将子查询改写。通常情况下,我们希望由内到外,先完成子查询的结果,然后在用子查询来驱动外查询的表,完成查询;但是mysql处理为将会先扫描外面表中的所有数据,每条数据将会传到子查询中与子查询关联,如果外表很大的话,那么性能上将会出现问题;

针对上面的查询,由于table_data这张表的数据有70W的数据,同时子查询中的数据较多,有大量是重复的,这样就需要关联近70W次,大量的关联导致这条sql执行了几个小时也没有执行完成,所以我们需要改写sql:SELECT t2.i_id,

SUM(t2.i_sell) AS sold

(SELECT DISTINCT i_id

FROM table_data

WHERE gmt_create >= '2011-10-07 00:00:00') t1,

table_data t2

WHERE t1.i_id = t2.i_id

GROUP BY t2.i_id;

我们将子查询改为了关联,同时在子查询中加上distinct,减少t1关联t2的次数;

改造后,sql的执行时间降到100ms以内。

mysql的子查询的优化一直不是很友好,一直有受业界批评比较多,也是我在sql优化中遇到过最多的问题之一,mysql在处理子查询的时候,会将子查询改写,通常情况下,我们希望由内到外,也就是先完成子查询的结果,然后在用子查询来驱动外查询的表,完成查询,但是恰恰相反,子查询不会先被执行;今天希望通过介绍一些实际的案例来加深对mysql子查询的理解。

下面我们来具体分析一下查询处理的每一个阶段MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作。其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来说是透明的,但是只有最后一个虚拟的表才会被作为结果返回。如果没有在语句中指定某一个子句,那么将会跳过相应的步骤FORM: 对FROM的左边的表和右边的表计算...
本系列blog源自前年写的SQL学习笔记,汇总一下发上来。(1月份发了前三篇笔记,原以为后面的笔记误操作删了,今天在硬盘里又找到了,一起发上来) -------------------------------- 不要在 子查询 中使用ORDER BY子句, 子查询 返回的中间结果是看不到的,对 子查询 排序没有意义。 子查询 是单个SELECT 语句 ,不能使用UNION连接多个SELECT 语句 作为 子查询 。...
主要参考博客: https://blog.csdn.net/yellowelephant/article/details/88064645?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-3&spm=1001.2101.3001.4242 ##创建员工信息表 create table emp( empno int(4) primary key, ename varchar(20), job varchar(
1. 子查询 MySQL 子查询 比较多,但是一般我们很少会写很复杂的 子查询 ,因为这样会使得 SQL 语句 很复杂,因此这里只是简单举个例子: select * from 数据表名1 where 字段1 = (select 字段2 from 数据表名2 where 字段3 = xx); 如上在 SQL 语句 中嵌套 SQL 语句 的情况叫 子查询 。 2. 查询 语句 的书写与 执行顺序 前面我们学到查询 语句 可以通过不同的子句来筛选相应的数据,那么当它们出现在一个 SQL 语句 中时,应该遵循什么书写顺序呢?应该遵循下面的
(8) DISTINCT <select_list> (1) FROM <left_table> (3) <join_type> JOIN <right_table> (2) ON <join_condition> (4) WHERE <where_...
MySQL 执行带有 子查询 语句 时,会先执行 子查询 ,然后将 子查询 的结果作为外部查询的条件或数据来源。具体 执行顺序 如下: 1. FROM子句:按照表之间的连接关系形成虚拟的表。 2. WHERE子句:按照指定条件筛选行。 3. GROUP BY子句:按照指定的列对结果进行分组。 4. HAVING子句:按照指定条件筛选分组。 5. SELECT子句:选择要查询的列。 6. DISTINCT关键字:去除重复行。 7. ORDER BY子句:按照指定的列对结果进行排序。 8. LIMIT子句:限制查询结果的行数。 在执行包含 子查询 语句 时, MySQL 会先执行 子查询 ,得到 子查询 的结果集,然后将该结果集作为外查询的条件或数据来源,再执行外查询。外查询的 执行顺序 与普通查询相同。 需要注意的是, 子查询 执行顺序 也遵循以上的规则,即先执行 子查询 的FROM子句、WHERE子句、GROUP BY子句、HAVING子句、SELECT子句、DISTINCT关键字、ORDER BY子句和LIMIT子句。
android browser ajax,#8343 (AJAX with 206 Response Triggers Error Callback in Android Browser) android browser ajax,#8343 (AJAX with 206 Response Triggers Error Callback in Android Browser)