下面我们来具体分析一下查询处理的每一个阶段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)