如何干涉MySQL优化器使用hash join
- GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
- GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
- 前言
- 实验
- 总结
前言
数据库的优化器相当于人类的大脑,大部分时候都能做出正确的决策,制定正确的执行计划,走出一条高效的路,但是它毕竟是基于某些固定的规则、算法来做的判断,有时候并没有我们人脑思维灵活,当我们确定优化器选择执行计划错误时该怎么办呢,语句上加hint,提示它选择哪条路是一种常见的优化方法。
我们知道Oracle提供了比较灵活的hint提示来指示优化器在多表连接时选择哪种表连接方式,比如use_nl
,no_use_nl
控制是否使用Nest Loop Join,use_hash
,no_use_hash
控制是否使用hash join。
但是MySQL长期以来只有一种表连接方式,那就是Nest Loop Join
,直到MySQL8.0.18版本才出现了hash join, 所以MySQL在控制表连接方式上没有提供那么多丰富的hint给我们使用,hash_join
与no_hash_join
的hint只是惊鸿一瞥,只在8.0.18版本存在,8.0.19及后面的版本又将这个hint给废弃了,那如果我们想让两个表做hash join该怎么办呢?
实验
我们来以MySQL8.0.25的单机环境做一个实验。建两个表,分别插入10000行数据,使用主键做这两个表的关联查询。
create table t1(id int primary key,c1 int,c2 int);
create table t2(id int primary key,c1 int,c2 int);
delimiter //
CREATE PROCEDURE p_test()
BEGIN
declare i int;
set i=1;
while i<10001 do
insert into t1 values(i,i,i);
insert into t2 values(i,i,i);
SET i = i + 1;
end while;
END;
//
delimiter ;
查询一下两表使用主键字段关联查询时实际的执行计划,如下图所示:
查询一下两表使用非索引字段关联查询时实际的执行计划,如下图所示:
从执行计划可以看出,被驱动表的关联字段上有索引,优化器在选择表连接方式时会倾向于选择Nest Loop Join,当没有可用索引时倾向于选择hash join。
基于这一点那我们可以使用no_index
提示来禁止语句使用关联字段的索引。
从上面的执行计划可以看出使用no_index提示后,优化器选择了使用hash join。
当索引的选择性不好时,优化器选择使用索引做Nest Loop Join是效率是很低的。
我们将实验的两个表中c1列的数据做一下更改,使其选择性变差,并在c1列上建普通索引。
update t1 set c1=1 where id<5000;
update t2 set c1=1 where id<5000;
create index idx_t1 on t1(c1);
create index idx_t2 on t2(c1);
当我们执行sql :
select t1.*,t2.* from t1 join t2 on t1.c1=t2.c1;
这个查询结果会返回大量数据,被驱动表的关联字段c1列的索引选择性差,此时选择hash join是更明智的选择,但是优化器会选择走Nest Loop Join。我们可以通过实验验证一下hash join 与 Nest Loop Join的性能差异。
可以看出使用hash join的耗时是使用Nest Loop Join的1/6,但是优化器根据成本估算时,使用Nest Loop Join的成本要比使用hash join的成本低很多,所以会去选择Nest Loop Join,这个时候就需要加上hint 提示禁止使用关联字段的索引,被驱动表上每次都全表扫描的代价是很高的,这样优化器估算后就会选择走hash join。
MySQL官方文档里提到用BNL
,NO_BNL
的hint提示来影响hash join的优化,但是经过实验证明,在表连接关联字段上没有可用索引时,优化器估算成本后不会对被驱动表使用BNL全表扫描的方式做嵌套循环连接,而是会选择使用hash join,那这样NO_BNL在这个场景下就没有用武之地了。
那么既然不用这个索引,把这个索引去掉不就可以了吗?为什么非要使用no_index的hint提示呢,我们要知道业务使用的场景何其多,此处不用,别处使用了这个索引效率可能会有大的提升啊,这个时候就凸显了hint的优势,只需要控制此语句的使用就好了。
总结
Nest Loop Join有其优势,它是response最快的连接方式,适用于返回数据量小的场景。当两个大表连接,返回大量数据,且关联字段的索引比较低效时,使用hash join就会比较高效,我们可以使用no_index的hint提示禁用关联字段的低效索引,促使优化器选择hash join。
如何干涉MySQL优化器使用hash join的更多相关文章
- 0104探究MySQL优化器对索引和JOIN顺序的选择
转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...
- 机智的MySQL优化器 --- is null
[介绍] 工作的越久越到的的问题越多,就越是觉得一些“老话”历久弥新:由于最近的学习计划是深入的学习一遍MySQL优化器:学习过程中的一些成果 也会发布到这里,一来是为了整理自己已经知道的和新学到的, ...
- mysql 8.0.18 hash join测试(内外网首文)
CREATE TABLE COLUMNS_hj as select * from information_schema.`COLUMNS`; INSERT INTO COLUMNS_hj SELECT ...
- 数据库 mysql 优化器原理
MySQL查询优化器有几个目标,但是其中最主要的目标是尽可能地使用索引,并且使用最严格的索引来消除尽可能多的数据行. 你的最终目标是提交SELECT语句查找数据行,而不是排除数据行.优化器试图排除数据 ...
- MySQL优化器cost计算
记录MySQL 5.5上,优化器进行cost计算的方法. 第一篇: 单表的cost计算 数据结构: 1. table_share: 包含了表的元数据,其中索引部分: key_info:一个key的结构 ...
- MySQL优化器功能开关optimizer_switch
MySQL 8.0新增特性 use_invisible_indexes:是否使用不可见索引,MySQL 8.0新增可以创建invisible索引,这一开关控制优化器是否使用invisible索引,on ...
- MySQL优化器 --- index_merge
[背景] 对于关系数据库中的一张表,通常来说数据页面的总大小要比较某一个索引占用的页面要大的多(上面说的索引是不包涵主键索引的); 更进一步我们可以推导出,如果我们通过读索引就能解决问题,那么它相比读 ...
- MySQL优化器不使用索引的情况
优化器选择不适用索引的情况 有时候,有乎其并没有选择索引而去查找数据,而是通过扫描聚集索引,也就是直接进行全表的扫描来得到数据.这种情况多发生于范围查找.JOIN链接操作等情况.例如 ; 通过SHOW ...
- 《Mysql - 优化器是如何选择索引的?》
一:概念 - 在 索引建立之后,一条语句可能会命中多个索引,这时,索引的选择,就会交由 优化器 来选择合适的索引. - 优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句. 二: ...
随机推荐
- ssh-修改ssh服务端口号
在启动selinux的状态下修改ssh的端口号 0.启动selinux setenforce 1 getenforce 1.修改sshd_config的Port为2234 查看2234 ...
- 不存在的!python说不给数据的浏览器是不存在的!
有时候我们些代码是总发此疑惑? 为什么别人采集 xx 网站的时候能成功,而我却总是不返回给数据出现这种原因时往往是我们没有给够伪装, 被识别了出来~ 就像人,你出门肯定是要穿衣服的对不,如果你不穿! ...
- Node.js精进(7)——日志
在 Node.js 中,提供了console模块,这是一个简单的调试控制台,其功能类似于浏览器提供的 JavaScript 控制台. 本系列所有的示例源码都已上传至Github,点击此处获取. 一.原 ...
- 记一次重复造轮子(Obsidian 插件设置说明汉化)
杂谈 #Java脚本 因本人英语不好在使用Obsidian时,一些插件的设置英文多令人头痛.故有写一个的翻译插件介绍和设置脚本的想法.看到有些前人写的一下翻译方法,简直惨目忍睹.竟然要手动.这个应该写 ...
- Gitlab分支策略建议指南
本文分支策略为总结各中小型企业常见做法(仅代表个人观点),在下才疏学浅,文章如有缺漏或不当之处,望各位帮忙指正.写此文也十分希望能起抛砖引玉之效. 据我所知,目前大部分无论是按瀑布/敏捷开发模型,就算 ...
- resultMap自定义映射(一对多)
collection:处理一对多和多对多的关系 1) POJO中的属性可能会是一个集合对象,我们可以使用联合查询,并以级联属性的方式封装对象.使用collection标签定义对象的封装规则 publi ...
- 攻防世界MISC进阶区--39、40、47
39.MISCall 得到无类型文件,010 Editor打开,文件头是BZH,该后缀为zip,打开,得到无类型文件,再改后缀为zip,得到一个git一个flag.txt 将git拖入kali中,在g ...
- Jenkins安装推荐插件前,更换插件源
网上找了很多都解决不了问题,直到看到jenkins-update-center,还有一个问题,就是尽量在实体机上装,感觉docker坑太多.... 安装jenkins,以Debian系为例 安装包在这 ...
- Java开发学习(十六)----AOP切入点表达式及五种通知类型解析
一.AOP切入点表达式 对于AOP中切入点表达式,总共有三个大的方面,分别是语法格式.通配符和书写技巧. 1.1 语法格式 首先我们先要明确两个概念: 切入点:要进行增强的方法 切入点表达式:要进行增 ...
- 典型相关分析CCA计算过程
本文介绍了CCA解决的问题,CCA原理的推导过程,以及对计算结果物理意义的解释.并且通过SPSS和R操作演示了一个关于CCA的例子.数据文件下载参考[8],SPSS输出结果文件下载参考[9],R代 ...