执行SQL如下
SELECT * FROM article STRAIGHT_JOIN article_comment ON article.author_id=author_id.user_id;
在这个流程里:
- 对驱动表article做了全表扫描 , 这个过程需要扫描1000行
- 从驱动表每读取一行数据都需要在article_comment表中进行全表扫描 , 没有使用索引就需要全表扫描
- 因此 , 每次都需要全表扫描被驱动表的数据
当然了 , MySQL也没有使用这种算法 , 而是用了分块嵌套查询的算法 , 这种思想在MySQL中很多地方都在使用
扩展
例如 , 索引是存储在磁盘中的 , 每次使用索引进行检索数据时会把数据从磁盘读入内存中 , 读取的方式也是分块读取 , 并不是一次读取完 。
假设现在操作系统需在磁盘中读取1kb的数据 , 实际上会操作系统读取到4kb的数据 , 在操作系统中一页的数据是4kb , 在innodb存储引擎中默认一页的数据是16kb 。
为什么MySQL会采用分块来读取数据 , 是因为数据的局部性原理 , 数据和程序都有聚集成群的倾向 , 在访问到一行数据后 , 在之后有极大的可能性会再次访问这条数据和这条数据相邻的数据 。
四、Block Nested-Loop Join使用简单嵌套查询的方式经过上文的分析肯定是不可取的 , 而是选择了分块的思想进行处理 。
这时 , 执行流程是这样的
- 从驱动表article中读取数据存放在join_buffer中 , 由于是使用的没有条件的select, 因此会把article全表数据放入内存
- 拿着join_buffer中的数据跟article_comment中的数据进行逐行对比
为了复现
Block Nested Loop
, 咔咔装了三个版本的MySQL , 分别为MySQL8 , MySQL5.5 , MySQL5.7在后两个版本中都使用的是Block Nested Loop
, 但在MySQL8中却发生了变化 。对于hash join 下期会聊到 , 在这个查询过程中 , 对表article、article_comment都做了一次全表扫描 , 因此扫描行数是2000 。
把article中的数据读取到join_buffer中是以无序数组的方式存储的 , 对于article_comment表中的每一行 , 都需要做1000次判断 , 那么就需要判断的次数就是1000*1000=1000万次 。
这时你发现使用分块嵌套循环跟简单嵌套查询扫描行数是一样的 , 但
Block Nested Loop
算法应用了join_buffer的这么一个内存空间 , 因此速度上肯定会比Simple
快很多 。五、总结本期我们用三个问题来总结全文 , 以帮助你更好的理解 。
第一个问题:能不能使用join?
通过三个演示案例 , 现在你应该知道当关联条件的列是被驱动表的索引时 , 是完全没有问题的 , 也就是说当使用索引嵌套查询时 , 是可以使用join的 。
但当使用的是分块嵌套查询 , 这种方式扫描行数为两张表行数的乘 , 扫描行数会非常的大 , 会占用大量的系统资源 , 所以这种算法的join是非常不建议使用的 。
因此当使用join时 , 最大可能的让关联查询的列为被驱动表的索引列 , 若不能达到这个条件则可以考虑表结构设计是否合理
第二个问题:如果使用join , 选择大表还是小表作为驱动表?
- 为什么许多人用过iPhone后,都不愿意再换回安卓?几点原因太真实
- 供应链管理|为什么有时候下载到99%就不动了?别着急,原因是这样的
- CPU|为什么你会觉得互联网买菜很便宜?
- 本文转自:大众日报□赵丰今天是3月15日国际消费者权益日。|观澜亭|科技向善共促消费公平:莫让算法变成算计
- 把算法开关交给消费者,好!
- 在2022年苹果春季发布会后|苹果“雷电数据线”为什么要卖到1000元吗
- 淘宝|为什么说景区大数据缺一不可?
- 前程无忧|压倒前程无忧最后的稻草:移动应用、算法推荐
- 互联网广告|宇宙飞船都能造,俄罗斯为什么没造出互联网巨头?
- 算法|95后扎堆“互联网”行业,年薪可达百万!