MySql join匹配原理
疑问
表:sl_sales_bill_head 订单抬头表 数据行:8474
表:sl_sales_bill 订单明细 数据行:8839
字段:SALES_BILL_NO 订单号
情况1
没有任何索引 sql语句
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
lh为主表 lb为子表
改一下sql语句
EXPLAIN select * from sl_sales_bill_head_copy1 lh
join sl_sales_bill_copy1 lb on lh.SALES_BILL_NO = lb.SALES_BILL_NO
疑问:为什么sql语句无论主表是哪个 lh都先执行
情况2
sl_sales_bill_head_copy1 的SALES_BILL_NO为主键索引
ALTER TABLE `sl_sales_bill_head_copy1` ADD PRIMARY KEY (`SALES_BILL_NO`) ;
sql语句1:
EXPLAIN select * from sl_sales_bill_head_copy1 lh
join sl_sales_bill_copy1 lb on lh.SALES_BILL_NO = lb.SALES_BILL_NO
sql语句2:
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
疑问:为什么无论怎么通过sql语句改变主表 始终是lb先执行
情况3
lh.SALES_BILL_NO创建索引
ALTER TABLE `sl_sales_bill_head_copy1` ADD PRIMARY KEY (`SALES_BILL_NO`) ;
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
where lb.SALES_BILL_NO='HP20190410000099'
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
where lh.SALES_BILL_NO='HP20190410000099'
都会正常走索引 同时也是lh先执行
如果改为lb的其他字段
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
where lb.id='0001c3fd44454a65a4122b259283f979'
无索引情况
ID有索引情况
变成了lb先执行
情况4
sl_sales_bill_head_copy1 的SALES_BILL_NO为主键索引
ALTER TABLE `sl_sales_bill_head_copy1` ADD PRIMARY KEY (`SALES_BILL_NO`) ;
SQL语句
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
sql语句
EXPLAIN select * from sl_sales_bill_copy1 lb
left join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
疑问:为什么left join没有走索引了
Join匹配原理
说明
mysql只支持一种算法Nested-Loop Join(嵌套循环链接),不像其他商业数据库可以支持哈希链接和合并连接,不过MySQL的Nested-Loop Join(嵌套循环链接)
Simple Nested-Loop
图片来源:InsideMySQ
R表为驱动表每扫描一行去S表找匹配的数据 这种算法是最耗时的 总扫描次数为驱动表行数*非驱动表行数
比如R表有200表数据 S表有100条 总扫描次数为200*100 可以看出这种算法效率最低
Index Nested-Loop Join
R表为驱动表每扫描一行 根据匹配条件通过索引去S表找 这种算法需要非驱动表有索引 一般我们on r.sid=s.id 索引时给非驱动表用的
比较高效
Block Nested-Loop Join
mysql 5.5对Simple Nested-Loop的优化 先扫描驱动表一定量(根据join_buffer_size来定) 放到join_buffer 然后遍历非驱动表 非驱动表每次匹配join_buffer里面的数据 减少扫描次数
比如我们的join_buffer最多只能存放r表3条数据 遍历R表 每遍历3条将数据放到join_buffer然后 然后再去遍历一次s表 每s表遍历一行跟join_buffer里面的数据进行匹配 遍历完成释放join_buffer 重复上面操作
在MySQL当中,我们可以通过参数join_buffer_size来设置join buffer的值,然后再进行操作。默认情况下join_buffer_size=256K
解决疑惑
情况1
lh数据条数8274 lb数据条数8721
疑问:为什么驱动表都是lh表
解答:mysqlsql优化器 默认会将小表作为驱动表
好处:
Block Nested-Loop Join算法
比如lh有4条数据 lb数据条数6 join_buffer是只能存放2条数据
计算规则为(驱动表遍历次数*驱动表行数)+(非驱动表遍历次数*非驱动表行数)=总遍历次数
我们将lb作为驱动表 扫描行数为(1*6)+(3*4)=18 总扫描行数
我们将lh作为驱动表 (1*4)+(2*6)=16 总扫描行数
可以发现小表作为驱动表扫描的行数更低
情况2:
lh数据条数8274 lb数据条数8721
疑问:为什么lh.SALES_BILL_NO为主键索引 驱动表始终是lb
解答:mysql优化器还是以小表为原则 如果大表关联关系有索引而小表没有则以有索引的表为驱动表
好处:
这里使用的Index Nested-Loop Join算法
如果使用lh驱动表 首先会遍历8274次 每次去lb去找 因为关联关系lb.SALES_BILL_NO没有做索引 所以非驱动表lb也会全表扫描 总扫描次数就变成8274*8721
如果使用lb为驱动表会遍历lb表每次通过SALES_BILL_NO去非驱动表lh找 因为lh做了索引 所以通过索引扫描一次就可以找到数据 总扫描次数:8274*1
情况3
lh数据条数8274 lb数据条数8721
疑问:为什么就lh.SALES_BILL_NO有主键索引 无论搜索条件是lb.SALES_BILL_NO还是lh.SALES_BILL_NO 都是lh先执行
解答:
因为on lb.SALES_BILL_NO=lh.SALES_BILL_NO where lb.SALES_BILL_NO='HP20190410000099'
这个时候虽然lb.SALES_BILL_NO没有索引 但是关联查找为lb.SALES_BILL_NO=lh.SALES_BILL_NO and lb.SALES_BILL_NO='HP20190410000099'
正常查找是lb全表扫描得到HP20190410000099然后去lh通过索引得到SALES_BILL_NO=lh.SALES_BILL_NO的数据
如果设置成lb.SALES_BILL_NO=lh.SALES_BILL_NO and lh.SALES_BILL_NO='HP20190410000099' 得到结果相同 以小表为驱动表原则sql优化器会优化为类似这样的语句查找
EXPLAIN select * from sl_sales_bill_copy1 lb
join sl_sales_bill_head_copy1 lh on lh.SALES_BILL_NO = lb.SALES_BILL_NO
where lb.id='0001c3fd44454a65a4122b259283f979'
lh.SALES_BILL_NO 有索引 然后lb.id无论有无索引都是 lb为驱动表 因为lb.id已经缩小了数据范围 小表原则 所以始终是lb为驱动表
情况4
因为left join相当于强制要求了lb为主表 虽然lh.SALES_BILL_NO有索引 但是join索引主要是给非驱动表用的 所以出现以上情况
join优化原则
尽量减少驱动表条数 非驱动表关联条件建立索引
虽然大部分会经过mysql优化器自动优化,复杂sql最好通过执行计划查看一下 是否有性能瓶颈
注意不要通过left join 影响sql优化器 将大表作为驱动表
记住join 索引只有在非驱动表上面才能体现作用
MySql join匹配原理的更多相关文章
- mysql join 底层原理
你知道 Sql 中 left join 的底层原理吗? 2019-09-10阅读 7130 https://cloud.tencent.com/developer/column/2367 01.前 ...
- mysql join优化原理
http://blog.itpub.net/22664653/viewspace-1692317/ http://itindex.net/detail/46772-%E4%BC%98%E5%8C%96 ...
- MySQL JOIN原理
先看一下实验的两张表: 表comments,总行数28856 表comments_for,总行数57,comments_id是有索引的,ID列为主键. 以上两张表是我们测试的基础,然后看一下索引,co ...
- MySQL JOIN原理(转)
先看一下实验的两张表: 表comments,总行数28856 表comments_for,总行数57,comments_id是有索引的,ID列为主键. 以上两张表是我们测试的基础,然后看一下索引,co ...
- mysql join 和left join 对于索引的问题
今天遇到一个left join优化的问题,搞了一下午,中间查了不少资料,对MySQL的查询计划还有查询优化有了更进一步的了解,做一个简单的记录: select c.* from hotel_info_ ...
- MYSQL索引结构原理、性能分析与优化
[转]MYSQL索引结构原理.性能分析与优化 第一部分:基础知识 索引 官方介绍索引是帮助MySQL高效获取数据的数据结构.笔者理解索引相当于一本书的目录,通过目录就知道要的资料在哪里, 不用一页一页 ...
- MySQL InnoDB 索引原理
本文由 网易云发布. 作者:范鹏程,网易考拉海购 InnoDB是 MySQL最常用的存储引擎,了解InnoDB存储引擎的索引对于日常工作有很大的益处,索引的存在便是为了加速数据库行记录的检索.以下是 ...
- 数据库MySQL 之 索引原理与慢查询优化
数据库MySQL 之 索引原理与慢查询优化 浏览目录 索引介绍方法类型 聚合索引辅助索引 测试索引 正确使用索引 组合索引 注意事项 查询计划 慢查询日志 大数据量分页优化 一.索引介绍方法类型 1. ...
- MySQL Optimization 优化原理
MySQL Optimization 优化原理 MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服务器.下图展示了MySQL的逻辑架构图. ...
随机推荐
- bzoj 1624: [Usaco2008 Open] Clear And Present Danger 寻宝之路【Floyd】
弗洛伊德之后按序列加起来即可 #include<iostream> #include<cstdio> #include<algorithm> using names ...
- svg image 图片无法铺满 circle 的问题解决
引子 使用d3.js绘制了力布图后,需要在circle中绘制图片,方法如下: // 绘制图片 drawPattern(gContainer) { let that = this; let gPatte ...
- less新手入门(三) 作为函数使用的Mixin、@import 导入指令 、@import 导入选项
五.作为函数使用的Mixin 从mixin返回变量 在mixin中定义的所有变量都是可见的,并且可以在调用者的作用范围中使用(除非调用者用相同的名称定义它自己的变量). .mixin(){ @widt ...
- thinkphp5 分页 paginate
tp5分页带参数的时候,用到 paginate 后面的几个参数 paginate有三个参数, 第一个必须表是每页分多少个[如果配置文件中设置了,可以不用] 第二个参数表是的是简洁分页,如果为true, ...
- 折半枚举(双向搜索)poj27854 Values whose Sum is 0
4 Values whose Sum is 0 Time Limit: 15000MS Memory Limit: 228000K Total Submissions: 23757 Accep ...
- 双摆模拟 python(转)
双摆 是 混沌理论 中的一个常见示例,这里通过 python 的作图工具包Matplotlib 来模拟双摆的运动过程: 注意:在 vs2017 中可以正确运行程序,在 cmd 环境下有时报错 &quo ...
- 410 Split Array Largest Sum 分割数组的最大值
给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组.设计一个算法使得这 m 个子数组各自和的最大值最小.注意:数组长度 n 满足以下条件: 1 ≤ n ≤ 1000 ...
- TensorFlow---基础---GFile
使用TensorFlow的时候经常遇到 tf.gfile.exists().... 关于gfile,一个googler是这样给出的解释: The main roles of the tf.gfile ...
- SqlServer知识点-操作xml
一.开发环境 SQL2010 二.开发过程 1.声明一个xml类型变量 DECLARE @xmlInfo XML; SET @xmlInfo = '<CompanyGroup> <C ...
- C语言学习(2)-GTK布局
首先了解下gtk中函数的定义格式: 记住下面几个格式看,下面的代码 声明变量:GtkAbc*abc=gtk_abc_new()声明控件; 赋值:gtk_abc_set_label(controlNam ...