MySQL子查询的优化
本文基于MySQL5.7.19测试
创建四张表,pt1、pt2表加上主键
mysql> create table t1 (a1 int, b1 int);
mysql> create table t2 (a2 int, b2 int);
mysql> create table pt1 (a1 int, b1 int, primary key (a1));
mysql> create table pt2 (a2 int, b2 int, primary key (a2));
向表中分别插入10000条数据
mysql> delimiter //
mysql> create procedure prod_dt()
-> begin
-> declare i int;
-> set i=0;
-> while i<10000 do
-> insert into t1(a1,b1) values(i,i+1);
-> insert into t2(a2,b2) values(i+1,i+2);
-> insert into pt1(a1,b1) values(i,i+1);
-> insert into pt2(a2,b2) values(i+1,i+2);
-> set i=i+1;
-> end while;
-> end;
-> //
Query OK, 0 rows affected (0.05 sec) mysql> delimiter ;
mysql> call prod_dt() ;
MySQL支持对简单SELECT查询中的子查询优化,包括:
1 简单SELECT查询中的子查询。
2 带有DISTINCT、ORDERBY、LIMIT操作的简单SELECT查询中的子查询。
# 没有主键,优化器进行了优化,子查询物化后和表t1进行连接。执行计划中没有子查询
mysql> explain extended select * from t1 where t1.a1<100 and a1 in (select a2 from t2 where t2.a2 >10);
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| 1 | SIMPLE | <subquery2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | 100.00 | Using where |
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 3.33 | Using where; Using join buffer (Block Nested Loop) |
| 2 | MATERIALIZED | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 33.33 | Using where |
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
3 rows in set, 2 warnings (0.00 sec) #有主键,优化器进行了优化。执行计划中没有子查询
mysql> explain extended select * from pt1 where pt1.a1<100 and a1 in (select a2 from pt2 where pt2.a2 >10);
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 89 | 100.00 | Using where |
| 1 | SIMPLE | pt2 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | abce.pt1.a1 | 1 | 100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec) mysql>
MySQL不支持对如下情况的子查询进行优化:
-带有UNION操作。
-带有GROUPBY、HAVING、聚集函数。
-使用ORDERBY中带有LIMIT。
-内表、外表的个数超过MySQL支持的最大表的连接数。
#有聚合函数,没有进行子查询优化
mysql> explain extended select * from t1 where t1.a1>(select min(t2.a2) from t2);
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 33.33 | Using where |
| 2 | SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
2 rows in set, 2 warnings (0.01 sec) mysql> explain extended select * from pt1 where pt1.a1>(select min(pt2.a2) from pt2);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
| 1 | PRIMARY | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 5000 | 100.00 | Using where |
| 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
2 rows in set, 2 warnings (0.00 sec) mysql>
MySQL支持哪些子查询的优化技术?
1 子查询合并技术 --> 不支持
#t2表上执行了2次子查询。如果支持子查询合并技术,则t2表上只执行一次子查询
mysql> explain extended select * from t1 where a1<4 and (exists (select a2 from t2 where t2.a2<5 and t2.b2=1) or exists (select a2 from t2 where t2.a2<5 and t2.b2=2) );
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 33.33 | Using where |
| 3 | SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 3.33 | Using where |
| 2 | SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 3.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
3 rows in set, 2 warnings (0.00 sec) mysql> #pt2表上执行了2次子查询。如果支持子查询合并技术,则pt2表上只执行一次子查询
mysql> explain extended select * from pt1 where a1<4 and (exists (select a2 from pt2 where pt2.a2<5 and pt2.b2=1) or exists (select a2 from pt2 where pt2.a2<5 and pt2.b2=2) );
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | PRIMARY | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 4 | 100.00 | Using where |
| 3 | SUBQUERY | pt2 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 4 | 10.00 | Using where |
| 2 | SUBQUERY | pt2 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 4 | 10.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
3 rows in set, 2 warnings (0.00 sec) mysql>
#人为的合并查询条件为“(t2.b2=1 OR t2.b2=2)”t2表上的子查询,只执行一次
mysql> explain extended select * from t1 where a1<10 and exists (select a2 from t2 where t2.a2<5 and (t2.b2=1 or t2.b2=2));
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 33.33 | Using where |
| 2 | SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 6.33 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
2 rows in set, 2 warnings (0.01 sec) mysql> explain extended select * from pt1 where a1<10 and exists (select a2 from pt2 where pt2.a2<5 and (pt2.b2=1 or pt2.b2=2));
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| 1 | PRIMARY | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 10 | 100.00 | Using where |
| 2 | SUBQUERY | pt2 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 4 | 19.00 | Using where |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec) mysql>
2 子查询展开(子查询反嵌套)技术 --> 支持得不够好
mysql> explain extended select * from t1, (select * from t2 where t2.a2 >10) v_t2 where t1.a1<10 and v_t2.a2<20;
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| 1 | SIMPLE | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 11.11 | Using where |
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 33.33 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
2 rows in set, 2 warnings (0.00 sec) mysql> explain extended select * from pt1, (select * from pt2 where pt2.a2 >10) v_t2 where pt1.a1<10 and v_t2.a2<20;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
| 1 | SIMPLE | pt2 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 9 | 100.00 | Using where |
| 1 | SIMPLE | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 10 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 2 warnings (0.00 sec) mysql> #IN子查询的例子,可以看出子查询被物化
mysql> explain extended select * from t1 where t1.a1<100 and a1 in (select a2 from t2 where t2.a2 >10);
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
| 1 | SIMPLE | <subquery2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | 100.00 | Using where |
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 3.33 | Using where; Using join buffer (Block Nested Loop) |
| 2 | MATERIALIZED | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 33.33 | Using where |
+----+--------------+-------------+------------+------+---------------+------+---------+------+-------+----------+----------------------------------------------------+
3 rows in set, 2 warnings (0.00 sec) mysql> #从查询执行计划看,子查询不存在,SQL语句被转换为内连接操作,这表明MySQL只有在针对主键列进行类似的子查询时,才把子查询上拉为内连接。所以,MySQL还是支持子查询展开技术的。
mysql> explain extended select * from pt1 where pt1.a1<100 and a1 in (select a2 from pt2 where pt2.a2 >10);
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 89 | 100.00 | Using where |
| 1 | SIMPLE | pt2 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | abce.pt1.a1 | 1 | 100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+-------------+------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec) mysql>
3 聚集子查询消除技术 --> 不支持
#MySQL认为,聚集子查询,只需要执行一次,得到结果后,即可把结果缓冲到内存中供后续连接或过滤等操作使用,没有必要消除掉子查询。
#另外,如果聚集子查询在索引列上执行,则会更快得到查询结果,更加能加速查询速度。
mysql> explain extended select * from t1 where t1.a1>(select min(t2.a2) from t2);
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
| 1 | PRIMARY | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 10362 | 33.33 | Using where |
| 2 | SUBQUERY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 10157 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+------+-------+----------+-------------+
2 rows in set, 2 warnings (0.00 sec) mysql> explain extended select * from pt1 where pt1.a1>(select min(pt2.a2) from pt2);
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
| 1 | PRIMARY | pt1 | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 5000 | 100.00 | Using where |
| 2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+------------------------------+
2 rows in set, 2 warnings (0.00 sec) mysql>
MySQL子查询的优化的更多相关文章
- [慢查优化]慎用MySQL子查询,尤其是看到DEPENDENT SUBQUERY标记时
案例梳理时间:2013-9-25 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助, ...
- MySQL 子查询(四)子查询的优化、将子查询重写为连接
MySQL 5.7 ref ——13.2.10.10优化子查询 十.子查询的优化 开发正在进行中,因此从长远来看,没有什么优化建议是可靠的.以下列表提供了一些您可能想要使用的有趣技巧.See also ...
- MySQL 子查询 EXISTS 和 NOT EXISTS(转)
MySQL EXISTS 和 NOT EXISTS 子查询 MySQL EXISTS 和 NOT EXISTS 子查询语法如下: SELECT ... FROM table WHERE EXISTS ...
- mysql子查询慢的问题
当你在用explain工具查看sql语句的运行计划时.若select_type 字段中出现"DEPENDENT SUBQUERY"时,你要注意了.你已经掉入了mysql子查询慢 ...
- MySQL子查询慢现象的解决
当你在用explain工具查看sql语句的执行计划时,若select_type 字段中出现“DEPENDENT SUBQUERY”时,你要注意了,你已经掉入了mysql子查询慢的“坑". 相 ...
- mysql数据库优化课程---16、mysql慢查询和优化表空间
mysql数据库优化课程---16.mysql慢查询和优化表空间 一.总结 一句话总结: a.慢查询的话找到存储慢查询的那个日志文件 b.优化表空间的话可以用optimize table sales; ...
- MySQL 子查询(一)
源自MySQL 5.7 官方手册 13.2.10 Subquery Syntax 〇.MySQL子查询介绍 子查询指的是嵌套在某个语句中的SELECT语句. MySQL支持标准SQL所要求的所有子查询 ...
- 第09章 MySQL子查询
第09章 MySQL子查询 子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入. SQL 中子查询的使用大大增强了 SELECT 查询的能力,因为很多时候查询需要 ...
- Mysql子查询、关联查询
mysql中update.delete.install尽量不要使用子查询 一.mysql查询的五种子句 where(条件查询).having(筛选).group by(分组).orde ...
随机推荐
- pdo_mysql安装不了或是安装后用不了的修复教程
目前发现wdOS及lanmp_wdcp的RPM包安装在部分系统下安装后,在安装pdo_mysql时无法安装或安装后无法使用的问题 如在安装时提示下如下 regenerate PHP parsers.c ...
- JAVA Eclipse如何导入已有的项目
File-Import,然后在弹出的窗口中输入exit,会自动提示下面的选项(已存在的项目) 把项目源代码放到Eclipse的工作目录,然后找到 导入完成
- JavaScript 时间、格式、转换及Date对象总结
悲剧的遇到问题,从前台得到时间,“Tue Jan 29 16:13:11 UTC+0800 2008”这种格式的,想再后台解析成想要的格式,但是在后台就是解析不了SimpleDateFormat也试着 ...
- jQuery开发技巧
jQuery 事件 - submit() 方法 $("form").submit(function(e){}); 当提交表单时,会发生 submit 事件. 该事件只适用于表单元素 ...
- Linux中禁用THP(Transparent Huge Pages)
一.简介 Centos6开始引入THP,Centos7时默认启用,用来提升内存性能. 二.说明 争对一些数据库,如Oracle.MariaDB.MongoDB.VoltDB在使用时,要求关闭此功能. ...
- thinkPHP 快速上手
http://www.kancloud.cn/manual/thinkphp5/118006 克隆项目 //首先克隆下载应用项目仓库 git clone https://github.com/top- ...
- Angularjs乱记
http://www.cnblogs.com/floor/p/6652313.html 在指令中使用filter DI规则 AngularJS注入规则 数据绑定 http://www.cnblogs. ...
- kube-proxy源代码分析
摘要:假设你对kube-proxy的工作原理有一定的了解.本文基于kubernetes v1.5代码对kube-proxy的源代码文件夹结构进行了分析,并以iptables mode为例进行了完整流程 ...
- Mysql查询优化之 触发器加中间表 方法优化count()统计大数据量总数问题
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6138288.html 在上一篇博文我们提到,分页有三种方法.其中,第三种是我们最常用的.然而,在实际应用过程中 ...
- FTP在CentOS上安装与使用
安装: yum install -y vsftpd 相关配置文件: /etc/vsftpd/vsftpd.conf //主配置文件,核心配置文件 /etc/vsftpd/ftpusers //黑名单, ...