MySQL 通过semi join 优化子查询
半连接是MySQL 5.6.5引入的,多在子查询exists中使用,对外部row source的每个键值,查找到内部row source匹配的第一个键值后就返回,如果找到就不用再查找内部row source其他的键值了。
测试环境
mysql> desc class;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| class_num | int(11) | NO | PRI | NULL | |
| class_name | varchar(20) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec) mysql> desc roster;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| class_num | int(11) | YES | | NULL | |
| student_num | int(11) | YES | | NULL | |
+-------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
roster表中记录的是学生的学号以及对应的教室,多个学生可能在同一个教室,所以字段class_num有重复值
class表中记录的是教室及对应的班级名,字段class_num为唯一值
如果要查询存在学生的班级有哪些
mysql> SELECT class.class_num, class.class_name FROM class INNER JOIN roster WHERE class.class_num = roster.class_num;
+-----------+------------+
| class_num | class_name |
+-----------+------------+
| 2 | class 2 |
| 3 | class 3 |
| 3 | class 3 |
+-----------+------------+
3 rows in set (0.00 sec)
可以通过distinct去除重复值,但这样做影响性能,所以通过子查询来得出结果
mysql> SELECT class_num, class_name FROM class WHERE class_num IN (SELECT class_num FROM roster);
+-----------+------------+
| class_num | class_name |
+-----------+------------+
| 2 | class 2 |
| 3 | class 3 |
+-----------+------------+
2 rows in set (0.00 sec)
优化器实际上是将子查询改写为了半连接
mysql> explain SELECT class_num, class_name FROM class WHERE class_num IN (SELECT class_num FROM roster);
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------------------------------------------------------------+
| 1 | SIMPLE | roster | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100.00 | Start temporary |
| 1 | SIMPLE | class | NULL | ALL | PRIMARY | NULL | NULL | NULL | 4 | 25.00 | Using where; End temporary; Using join buffer (Block Nested Loop) |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec) mysql> show warnings;
+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note | 1003 | /* select#1 */ select `test`.`class`.`class_num` AS `class_num`,`test`.`class`.`class_name` AS `class_name` from `test`.`class` semi join (`test`.`roster`) where (`test`.`class`.`class_num` = `test`.`roster`.`class_num`) |
+-------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
Start temporary 和 End temporary的使用表明使用了临时表来去除重复值
如果 select_type 的值为MATERIALIZED 并且 字段 rows的输出是<subquery则表明临时表用于了物化表N>select_typevalue ofMATERIALIZEDand rows with atablevalue of<subquery.N>
如果子查询符合准则(参考文献:http://dev.mysql.com/doc/refman/5.7/en/subquery-optimization.html#semi-joins),MySQL将其转化为semi-join并从以下策略中作出基于cost的选择
Convert the subquery to a join, or use table pullout and run the query as an inner join between subquery tables and outer tables. Table pullout pulls a table out from the subquery to the outer query.
Duplicate Weedout: Run the semi-join as if it was a join and remove duplicate records using a temporary table.
FirstMatch: When scanning the inner tables for row combinations and there are multiple instances of a given value group, choose one rather than returning them all. This "shortcuts" scanning and eliminates production of unnecessary rows.
LooseScan: Scan a subquery table using an index that enables a single value to be chosen from each subquery's value group.
Materialize the subquery into a temporary table with an index and use the temporary table to perform a join. The index is used to remove duplicates. The index might also be used later for lookups when joining the temporary table with the outer tables; if not, the table is scanned
不确定的内容不敢随意翻译,摘出来原汁原味的文献内容
系统变量optimizer_switch中的semi join 标签控制着半连接是否可用,5.6默认是开启的
MySQL 通过semi join 优化子查询的更多相关文章
- MySQL 使用JOIN优化子查询
1.数据准备 mysql> select * from student; +----+--------+----------+---------+-------------+ | id | na ...
- paip.sql索引优化----join 代替子查询法
paip.sql索引优化----join 代替子查询法 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.n ...
- SQL Server中INNER JOIN与子查询IN的性能测试
这个月碰到几个人问我关于"SQL SERVER中INNER JOIN 与 IN两种写法的性能孰优孰劣?"这个问题.其实这个概括起来就是SQL Server中INNER JOIN与子 ...
- join和子查询的一点点思考
代码和表设计过程中,为了考虑数据库的范式,通常导致需要join多张表或子查询, 如报表场景, 可此种方式在大数据量的 情况下,效率较低. 如果能做适量的数据冗余,便可以减少join或子查询,效率较高 ...
- Mysql-SQL优化-子查询替代LEFT JOIN
表A:批次信息表, 表B:实际批次明细表, Mysql版本:5.6.36 两表之间的数据体量差异:表B是表A的10000倍. 经过结转,表B通常保留 1千5百万数据.表A就是1千多条数据. 计算近24 ...
- MySql优化子查询
用子查询语句来影响子查询中产生结果rows的数量和顺序. For example: SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM ...
- Mysql基本用法-left join、right join、 inner join、子查询和join-02
left join #左连接又叫外连接 left join 返回左表中所有记录和右表中连接字段相等的记录 test_user表 phpcvs表 SQL: select * from test_use ...
- Database学习 - mysql 数据库 多表/复合/子 查询
多表查询 多表查询,基本规则,通过两表有关联字段的进行条件匹配查询 内连接查询 方式一: SELECT 查看字段名[,查看字段名] FROM 一表名,二表名 WHERE 一/二表.字段 = 一/二表. ...
- 优化子查询sql语句为内连接
背景: 希望提高查询的效率,从sql语句中频繁出现的子查询入手. 数据表如下:Student表中的CityCode对应于City表中的Code. Student表: ...
随机推荐
- fullpage 单屏高度超过屏幕高度,实现单屏内可以滚动并解决手机端单屏高度不正确的问题
最近接触了好几次jquery.fullpage.js这个插件,实现整屏的滑动,效果很炫,用fullpage来实现也很简单,但是也碰到了一些问题和大家分享一下 1.单屏高度超过屏幕高度,实现单屏的滑动 ...
- 02.JavaScript 面向对象精要--函数
在JavaScript中,函数其实也是对象.是函数不同于其他对象的特点是:函数存在一个被称为[[Call]]的内部属性.[[Call]]属性是函数独有的,表明该对象可以被执行.ECMAScript 定 ...
- try-catch
try{ // 程序代码 }catch(异常类型1 异常的变量名1){ // 程序代码 }catch(异常类型2 异常的变量名2){ // 程序代码 }catch(异常类型2 异常的变量名2){ // ...
- AX2012单元格显示颜色 displayOption
public void displayOption(HV_WMSLocationStatusHistory _record, FormRowDisplayOption _options){ #d ...
- text-transform属性
text-transform -- 定义文本的大小写状态,此属性对中文无意义 取值:capitalize | uppercase | lowercase | none | inherit capita ...
- LoadRunner ERROR: java.lang.NumberFormatException
Loadrunner中使用lr_xml_get_values()获取服务端返回的字符串LcsId,LcsId为double,需要将该值转换为 int 后传入下一次请求中. 报错如下:Error is ...
- js/jquery 去掉空格.回车.换行
本文转载自 http://hi.baidu.com/niubore/item/426532faab4ddcc50dd1c8f9 Jquery:$("#accuracy").val( ...
- 本地搭建PHP环境后进入应用失败
进入localhost/wordpress或者其他应用,直接出现类似以下这种情况: 解决方法是修改tomcat的配置文件httpd.conf中: <IfModule dir_module> ...
- map erase iterator
错误写法: map<int, int> m; for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) ...
- SharpDevelop的亮点—优化提示
用惯了Visual Studio,像被惯坏了孩子,很难适应别的IDE. 上个月Win7系统崩溃了,重装后,自然VS也没了.这次下定决心,绝对不在自己电脑上用VS了,于是重新捡起SharpDevel ...