MySQL 如何执行关联查询
本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/51
当前mysql执行的策略很简单:mysql对任何关联都执行嵌套循环操作,即mysql先在一个表中循环取出单条数据,然后再嵌套循环到下一个表中寻打匹配的行,依次下去,直到描述到所表表中匹配的行为止。然后根据各个表匹配的行,返回查询中需要的各个列。mysql会尝试在最后一个关联表中打到所有匹配的行,如果最后一个关联表无法找到更多的行以后,mysql返回到上一层次关联表,看是否能够找到更多的匹配记录,依此类推迭代执行。
按照这样的方式查找第一条表记录,再嵌套查询下一个关联表,然后回溯到上一个表,在mysql中是通过嵌套循环的方式来实现的--正如其名‘嵌套循环关联’。请看下面的例子中的简单查询:
select tbl1.col1,tbl2.col2
from tbl1 inner join tbl2 using(col3)
where tbl1.col1 in(5,6);
假设mysql按照查询中的表顺序进行关联操作,我们则可以用下面的伪代码表示mysql将如何完成这个查询:
outer_iter = iterator_over tbl1 where col1 in(3,4)
outer_row = outer_iter.next
while outer_row
inner_iter = iterator over tbl2 where col3=outer_row.col3
inner_row = inner_iter.next
while inner_row
output[outer_row.col1,inner_row.col2]
inner_row = inner_iter.next
end
out_row = outer_iter.next
end
上面的执行计划对于单表查询和多表关联查询都适用,如果是一个单表查询,那么只需要完成上面的外层的基本操作。对于外连接和上面的执行过程任然适用。例如我们将上面的查询修改如下:
SELECT tbl1.col1 ,tbl2.col2 FROM tbl1 left outer join tbl2 using (col3) WHERE tbl1.col1 in (3,4)
对应的伪代码:
outer_iter = iterator over tbl1 where col1 in(3,4)
outer row = outer_iter.next
while outer_row
inner_iter = iterator over tbl2 where col3 = outer_row.col3
inner_row = inner_iter.next
if inner row -> 手动加粗
while inner_row
out_put [outer_row.col1,inner_row.col2]
inner_row = inner_iter.next
end
else -> 手动加粗
out_put[outer_row.col1,NULL] -> 手动加粗
end
outer_row = outer_iter.next
end
从上面两个例子也可以看出,对于主表来说,是先进行主表的where条件筛选,再进行表联接,而不是先进行整表联接再进行where条件的筛选。
举个例子:
数据表结构:
mysql> create table a(
-> id int unsigned not null primary key
-> );
mysql> create table b like a;
表中数据:
mysql> select * from a;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+----+
5 rows in set (0.00 sec)
mysql> select * from b;
+----+
| id |
+----+
| 4 |
| 5 |
| 6 |
| 7 |
+----+
4 rows in set (0.00 sec)
explain查询:
mysql> explain select a.id as aid,b.id as bid from a left join b using(id) where a.id>3;
+----+-------------+-------+--------+---------------+---------+---------+----------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+--------------------------+
| 1 | SIMPLE | a | range | PRIMARY | PRIMARY | 4 | NULL | 3 | Using where; Using index |
| 1 | SIMPLE | b | eq_ref | PRIMARY | PRIMARY | 4 | com.a.id | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+--------------------------+
2 rows in set (0.00 sec)
可以看出,首先在a表上进行范围查询,筛选出a.id>3的数据,然后在进行"嵌套查询"。
注意,on后面的筛选条件主要是针对的是关联表,而对于主表筛选并不适用,比如:
mysql> select a.id as aid,b.id as bid from a left join b on a.id=b.id and a.id>3;
+-----+------+
| aid | bid |
+-----+------+
| 1 | NULL |
| 2 | NULL |
| 3 | NULL |
| 4 | 4 |
| 5 | 5 |
+-----+------+
5 rows in set (0.00 sec)
mysql> explain select a.id as aid,b.id as bid from a left join b on a.id=b.id and a.id>3;
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-------------+
| 1 | SIMPLE | a | index | NULL | PRIMARY | 4 | NULL | 5 | Using index |
| 1 | SIMPLE | b | eq_ref | PRIMARY | PRIMARY | 4 | com.a.id | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+----------+------+-------------+
2 rows in set (0.00 sec)
我们发现a表的id<=3的数据并未被筛选走,explain的结果是a表进行了index类型的查询,即主键索引的全部扫描。
如果在on的筛选条件是针对b表的呢,情况会怎么样?
下面的例子数据表结构和数据变了,我们只关注查询的结果区别:
mysql> select * from a left join b on a.data=b.data and b.id<=20;
+----+------+------+------+
| id | data | id | data |
+----+------+------+------+
| 1 | 1 | NULL | NULL |
| 2 | 2 | NULL | NULL |
| 3 | 3 | NULL | NULL |
| 4 | 4 | 1 | 4 |
| 4 | 4 | 6 | 4 |
| 4 | 4 | 11 | 4 |
| 4 | 4 | 16 | 4 |
| 5 | 5 | 2 | 5 |
| 5 | 5 | 7 | 5 |
| 5 | 5 | 12 | 5 |
| 5 | 5 | 17 | 5 |
+----+------+------+------+
11 rows in set (0.00 sec)
mysql> select * from a left join b on a.data=b.data where b.id<=20;
+----+------+------+------+
| id | data | id | data |
+----+------+------+------+
| 4 | 4 | 1 | 4 |
| 5 | 5 | 2 | 5 |
| 4 | 4 | 6 | 4 |
| 5 | 5 | 7 | 5 |
| 4 | 4 | 11 | 4 |
| 5 | 5 | 12 | 5 |
| 4 | 4 | 16 | 4 |
| 5 | 5 | 17 | 5 |
+----+------+------+------+
8 rows in set (0.00 sec)
由此,我们可以根据伪码来分析两者的区别:
outer_iter = iterator over a
outer row = outer_iter.next
while outer_row
inner_iter = iterator over b where data = outer_row.date where id<=20
inner_row = inner_iter.next
if inner row
while inner_row
out_put [outer_row,inner_row]
inner_row = inner_iter.next
end
else
out_put[outer_row,NULL]
end
outer_row = outer_iter.next
end
outer_iter = iterator over a
outer row = outer_iter.next
while outer_row
inner_iter = iterator over b where data = outer_row.date ->手动加粗
inner_row = inner_iter.next
if inner row
while inner_row
out_put [outer_row,inner_row]
inner_row = inner_iter.next
end
else
out_put[outer_row,NULL]
end
outer_row = outer_iter.next
end
left join的结果集中 where b.id<=20 ->手动加粗
参考资料:《高性能MySQL》
MySQL 如何执行关联查询的更多相关文章
- MySQL如何执行关联查询
MySQL中‘关联(join)’ 一词包含的意义比一般意义上理解的要更广泛.总的来说,MySQL认为任何一个查询都是一次‘关联’ --并不仅仅是一个查询需要到两个表的匹配才叫关联,索引在MySQL中, ...
- mysql如何执行关联查询与优化
mysql如何执行关联查询与优化 一.前言 在数据库中执行查询(select)在我们工作中是非常常见的,工作中离不开CRUD,在执行查询(select)时,多表关联也非常常见,我们用的也比较多,那么m ...
- Mysql多表表关联查询 inner Join left join right join
Mysql多表表关联查询 inner Join left join right join
- JDBC MySQL 多表关联查询查询
public static void main(String[] args) throws Exception{ Class.forName("com.mysql.jdbc.Driver&q ...
- MySQL多表关联查询与存储过程
-- **************关联查询(多表查询)**************** -- 需求:查询员工及其所在部门(显示员工姓名,部门名称) -- 1.1 交叉连接查询(不推荐.产生笛卡尔乘积 ...
- mysql 无法执行select查询
场景:mysql无法执行select命令查询,对于已存在的数据库,除了mysql.information_schema数据库,其它诸如nova.keystone.cinder等数据库都有此现象. 日志 ...
- MySQL 三种关联查询的方式: ON vs USING vs 传统风格
看看下面三个关联查询的 SQL 语句有何区别? 1SELECT * FROM film JOIN film_actor ON (film.film_id = film_actor.film_id) 2 ...
- MySQL多表关联查询数量
//多表关联查询数量select user, t1.count1, t2.count2from user tleft join ( select user_id, count(sport_type) ...
- [MySQL]多表关联查询技巧
示例表A: author_id author_name 1 Kimmy 2 Abel 3 Bill 4 Berton 示例表B: book_id author_id start_date end_da ...
随机推荐
- Windows server2012如何运行Javaweb项目?
最近用java写了个小项目,想要部署到服务器,于是买了个Windows server2012,但是不知道怎么部署,后来才知道需要配置java运行环境.经过一番研究最终搞定了.下边是我的个人总结,由于是 ...
- sklearn 划分数据集。
1.sklearn.model_selection.train_test_split随机划分训练集和测试集 函数原型: X_train,X_test, y_train, y_test =cross_v ...
- head first python菜鸟学习笔记(第三章)
1.os.chdir()切换到指定目录下,os.getcwd(),得到当前目录. >>> import os>>> os.chdir('D:\\CodeDocume ...
- Python之文件的基本操作
在python中,对文件的基本操作一共有如下四种: 1.打开文件 file_obj = open("文件路径","模式") 常用的打开文件模式有: r:以只读方 ...
- (新)elasticsearch6.0版本安装head插件
ES6.0版本安装head插件 1.1 前言 不知道是我电脑问题还是最近的开源软件都比较**,mysql和elasticsearch新版本变动都比较大. elasticsearch6.0貌似已经不支持 ...
- Ocelot网关
Ocelot是一个.net core框架下的网关的开源项目,下图是官方给出的基础实现图,即把后台的多个服务统一到网关处,前端应用:桌面端,web端,app端都只用访问网关即可. Ocelot的实现原理 ...
- bundles.Add( )下无法绑定后缀为min.css的文件
1.问题描述: 在绑定css的时候,除了后缀名为.min.css的文件,在render.style()不显示外,其他的css都正常加载, 2.解决办法: 这个是我在调试了几遍之后发现的规律,然后解决办 ...
- gis电子地图开发公司面临的挑战和机遇
从上个世纪90年代开始电子地图应用就已经收到人们的关注,但是由于时代的局限性和市场经济发展的不成熟.地理信息系统系统的应用并没有得到很好的利用.只有少数的国家机构和军事系统才能够使用这些应用.随着技术 ...
- pipelineDB初体验
官网:http://www.pipelinedb.com/ pipelineDB是基于postgres的stream数据库.完全兼容pg的东西. 由于产品需要解决性能这块瓶颈,老大让试试这款基于流计算 ...
- VS2015 密钥key
亲测可用: HMGNV-WCYXV-X7G9W-YCX63-B98R2