Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解
Mysql hash join之classic hash join CHJ过程详解
hash join的历史
优化器里的hash join算法在SQL Server、Oracle、postgress等数据库早已实现,而Mysql在8.0.18之后才支持。在8.0.18之前mysql只支持嵌套循环关联(nested loop join),这其中最简单就是简易嵌套循环关联simple nestloop join,随后mysql做了改进进而支持block nestloop join, index nestloop join and batched key access等算法,这也是hash join算法被推迟实现的部分原因。
hash join的概述
提到hash join之前自然得说Nestloopjoin,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再拿每次对应的值去匹配、循环遍历内部的表(M条)。这样显然会有M*n的计算复杂度。如果能将外部表先装载到内存,然后再做内部表的匹配、遍历,计算的复杂度就会大大降低,这就是hash join的思想。
hash join的类型
hash join 从具体实现上又分为:
1经典hash join(In-Memory Join或classic hash join或CHJ)
2 磁盘分区hash join (On-Disk Hash Join)
3 Grace Hash Join
4 混合hash join(hybrid hash join)
hash join应用场景
hash join主要应用在以下条件:
1两个或多个表至少包含一个等值条件关联时。
2 关联的字段上没有索引。
3 关联条件可以是原始字段或者表达式(如 T1.col1+T1.col2 = T2.col3+T2.col4).
4 关联条件等号的两表只能出现一张表。
5 补充,可能使用到hash join的SQL写法示例:
CREATE TABLE t1 (t1_1 INT, t1_2 INT);CREATE TABLE t2 (t2_1 INT, t2_2 INT)SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1 AND t1.t1_2 = t2.t2_2);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 = t2.t2_1 AND t2.t2_2 > 43);SELECT * FROM t1 JOIN t2 ON (t1.t1_1 + t1.t1_2 = t2.t2_1);SELECT * FROM t1 JOIN t2 ON (FLOOR(t1.t1_1 + t1.t1_2) = CEIL(t2.t2_1 = t2.t2_2));
In-Memory Join classic hash join
经典hash join(classic hash join)简称CHJ,该算法由两部分构成,一是构建哈希表(hash table)过程,二是探测、匹配(probe)过程。
以有如下查询和表格结构为例:
CREATE TABLE t1 (foo INT);
CREATE TABLE t2 (bar INT);
insert into t1 values(12);
insert into t2 values(34);
… ... -- 插入数据省略
SELECT * FROM t1 JOIN t2 on (t1.foo = t2.bar);
构建哈希表:
1 当两个表以含等值条件方式关联时其中一个表会被指定为构建表,该表会以哈希表(哈希的值来自于等值条件里的字段)的形式读入内存。
2 假设这里t1表被指定为构建表,那么将会通过哈希函数产生哈希表,这里t1的foo字段是是哈希函数里的键。
探测阶段:
此时join里的另外个表即t2作为探测表,在构建完成后,开始从t2探测表作为输入。这时以t2的bar (t1、t2两表关联时t2的字段)作为哈希的键,同时该键是用来匹配内存里的t1生成的哈希表。一旦匹配到记录则意味着找到目标,这个按照每一行匹配的过程就做探测过程。
In-Memory Join过程示意
执行计划查看In-Memory Join
EXPLAIN ANALYZE
SELECT CountryCode, country.Name AS Country,
city.Name AS City, city.District
FROM world.country IGNORE INDEX (Primary)
INNER JOIN world.city IGNORE INDEX (CountryCode)
ON city.CountryCode = country.Code
WHERE Continent = 'Asia';-- 数据库来自mysql官网示例数据库world
-- 结果
EXPLAIN
-> Inner hash join (world.city.CountryCode = world.country.`Code`) (cost=13870.82 rows=595) (actual time=58.807..134.662 rows=1766 loops=1)-> Table scan on city (cost=0.80 rows=4046) (actual time=30.193..95.386 rows=4079 loops=1)-> Hash-> Filter: (world.country.Continent = 'Asia') (cost=30.90 rows=34) (actual time=21.446..28.489 rows=51 loops=1)-> Table scan on country (cost=30.90 rows=239) (actual time=21.435..28.338 rows=239 loops=1)
执行示例
过程介绍
Step1:Country的Code字段会被哈希函数哈希并保存在关联缓存(即哈希表)内(join buffer)。
Step2:然后通过和step1里一样的哈希函数哈希的字段CountryCode进行表扫描(table scan)遍历city表里的每一行。
Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解相关推荐
- Mysql 优化器内部JOIN算法hash join On-Disk Hash Join Grace Hash Join Hybrid hash join过程详解
Mysql 各种hash join算法讲解 hash join的概述 提到hash join之前自然得说Nest loop join,以两个表的关联为例,它其实是个双层循环,先遍历外层的表(n条),再 ...
- MySQL优化器如何预估查询成本
MySQL有哪些查询成本 MySQL 执行一个查询可以有不同的执行方案.在我们开发过程中,所有写过的sql语句都会丢给MySQL端的优化器.由优化器判断并选择其中成本最低,或者说代价最低的那种方案去真 ...
- MySQL优化器_MySQL查询优化器
MySQL优化器 MySQL架构图 讲到MySQL,就绕不开他的架构图.MySQL是一个经典的C/S架构.服务器这边分两层:第一层是Server层,第二层是存储引擎.Server层处理主要的业务操作流 ...
- MySQL优化器:index merge介绍
在MySQL官方手册上,关于index merge的介绍非常非常少.甚至还有不少误导的地方,这次把5.1版本关于此类优化处理的代码细看了一遍,以案例的方式介绍了各种实用index merge访问类型的 ...
- mysql not in优化_98%的人不知道的MySQL优化器原理
| 作者 梁东阳,数据库研发中心数据库内核工程师,负责腾讯云MySQL的内核开发. 在日常运维中,相信不少人都收藏了很多关于查询优化的方法论和小技巧,但是仔细想想,你真的了解这些优化背后的原理吗? ...
- MySQL优化器选错索引情况
MySQL优化器选错索引情况 1. 优化器选错索引 2. 优化器的逻辑 3. 索引选择异常和处理 1. 优化器选错索引 之前MySQL架构以及执行sql查询语句介绍过MySQL优化器可以帮助我们优化s ...
- MySQL 优化器原来是这样工作的
文章目录 优化器概述 逻辑转换 基于成本的优化 控制优化程度 设置成本常量 数据字典与统计信息 控制优化行为 优化器和索引提示 总结 大家好,我是只谈技术不剪发的 Tony 老师.我们在 MySQL ...
- mysql优化器怎么选择索引,为什么MySQL查询优化器会选择聚集主索引上的二级索引?...
为什么Mysql优化器在执行'select * from lookup'而没有order by子句时选择二级索引. 它只是一个侥幸,或者这是一个幕后优化,假设你添加了一个二级索引,它比主键更重要. 我 ...
- mysql优化器放弃索引场景,MYSQL索引优化(索引失效场景)
学习mysql是作为一名Java工程师必不可少的事情,但是我们只认识mysql的增删查改建表等等的sql语句其实远远不够的,对于进阶mysql来说,索引是一个很重要的部分.下面我们就来说一下在mysq ...
最新文章
- R语言ggplot2可视化:使用gganimate包和gapminder包为生成的动画文件gif设置尺寸、分辨率
- 3种时间序列混合建模方法的效果对比和代码实现
- 卫星发现一个重要信号:路上货车跑起来
- 那些做的“不够好”的父母,他们可能已经做到了自己的100分
- Java中的static———静态变量
- eoj程序设计基础(基于 C 语言)1067
- go语言爬虫教程python_Go语言爬虫 - Go语言中文网 - Golang中文社区
- xftp怎么有root权限_许多人都不懂的Linux系统里的特殊权限!!你真的了解嘛?...
- 第二节 CSS入门介绍
- (Android开发辅助工具)动态广播注册解注工具
- 汽车汽配行业DMS渠道商系统精准掌握渠道库存,提升市场响应能力
- 电力仿真需要学的软件?5款有实力的电力仿真软件
- win7系统使用高版本node.js
- 新能源车车牌识别c++
- 华为鸿蒙魔法闪投大小屏幕互动,「老熊科普」魔法闪投,荣耀智慧屏就是你的“超级大手机”...
- 十三届蓝桥杯基础知识大全
- 闲鱼如何保障交易链路质量
- 财路网每日原创推送:隐私计算让人工智能更智能
- python pdf转word的两种方法
- 约旦稳居B组头名 澳大利亚绝杀叙利亚出线
热门文章
- wxWidgets:wxFrame类用法
- 一个简单的 Hello world! 例子使用 boost::mpi::group 和 boost::mpi::broadcast()
- boost::mp11::mp_third相关用法的测试程序
- boost::mp11::mp_size相关用法的测试程序
- boost::math模块通过 Gauss 和 Gauss-Kronrod 正交的数值积分
- Boost:不受约束的bimap双图的测试程序
- VTK:可视化算法之PineRootDecimation
- VTK:PolyData之WeightedTransformFilter
- Qt发布到Google Play
- Qt Creator配置编辑器