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表: ...
随机推荐
- 冰球项目日志4-yjw
小组讨论 我们组编程主要分成三个模块,各自负责自己的编程与测试. 杨静梧:确定击球算法编程.输入:冰球位置,速度大小方向:输出:撞击时冰球中心位置. 曹迦勒:确定击球手速度,位置.输入:撞击时冰球中心 ...
- 还有 3 天,苹果就要关上 HTTP 大门了
版权声明:本文由贺嘉 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/274113001482113656 来源:腾云阁 h ...
- iOS适配https详解
马上就要元旦了,网上流传元旦之后苹果会对所有的app进行https的验证,据说会拒绝所有没有使用https的app.但是后来又听说是我们开发者误解了,元旦过后还是会支持http,不过开发者需要说明为什 ...
- Ajax聊天
结构: index.html <!DOCTYPE html> <html> <head> <title>index.html</title> ...
- [Java] 特殊正则-替换字符串
public class Test { public static void main(String[] args) { String str = "2412rhttp://192.168. ...
- (46) odoo核心文档分享
*前言: 要掌握一个系统,还得有扎实的基础,最好的方法,阅读核心文档 然后去实践. *核心文档列表如下: odoo8官方参考.pdf 链接: http://p ...
- 实现View的移动的方法总结
btw:这篇博客的内容其实算是<Android开发艺术探索>的一篇读书笔记,在书本的知识上加了一点自己的理解,并用自己的话描述出来.<Android开发艺术探索>是一本不错的书 ...
- Callable与Future的介绍
http://www.cnblogs.com/whgw/archive/2011/09/28/2194760.html
- Convert Sorted List to Binary Search Tree [LeetCode]
Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...
- 十天学会<div+css>横向导航菜单和纵向导航菜单
纵向导航菜单及二级弹出菜单 纵向导航菜单:一级菜单 <head><style type="text/css">body { font-family: Ver ...