侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

数据库哈希连接详解(MySQL新特性)

数据库  /  管理员 发布于 8年前   456

概述

很长一段时间,MySQL 执行 连接 的唯一算法是 嵌套循环算法 ( nested loop algorithm) 的变体 ,但是 嵌套循环算法 在某些场景下非常低效,也是 MySQL 一直被诟病的一个问题。

随着 MySQL 8.0.18 的发布,MySQL Server 可以使用哈希连接(hash join),这篇文章将会简单介绍下哈希连接如何实现,看看在 MySQL 中它是如何工作的,何时使用它,有什么限制。

推荐学习:MySQL教程

哈希连接简介

什么是哈希连接?

哈希连接是一种用于关系型数据库中的连接算法,只能用于有等连接条件的连接中(on a.b = c.b)。它通常比 嵌套循环 算法 更高效(探测端非常非常小除外),尤其是在没有命中索引的情况下。

简单来说,哈希连接算法就是先把一张小表加载到内存哈希表里,然后遍历大表的数据,逐行去哈希表中匹配符合条件的数据,返回到客户端。

b3a0ae04b9a46f1ebd6d461a09197dc.png

(哈希表只是示例,方面理解,实际 hash 的 key 是连接的值,value 是数据行链表)

通常将 哈希连接 分为两个阶段,构建阶段(build phase)和探测阶段(probe phase)。在构建阶段,先选择合适的表作为「构建输入」,构建哈希表,然后再依次遍历另一个「探测输入」表记录去探测哈希表查找符合连接条件的记录。

以上图为例,查询城市对应的省份。我们假设 city 为 构建输入,在构建阶段,服务器构建一个 city 哈希 表 ,遍历 city 表,将行依次放进 哈希表,键为 hash(province_id),值为对应的 城市行。`

在探测阶段,服务器开始从 探测输入(province) 读取行。对于每一行都使用 hash(province.province_id) 值作为查找键探测哈希表以匹配行。

也就是,构建输入能全部被加载到内存的情况下,仅扫每个探测行一次,使用常数时间查找就可以查找到两个输入之间匹配的行。

数据太多不能放入内存怎么办?

将 构建输入 全部加载到内存中无疑是效率最高的,但在有些情况下,内存不足以将整张表加载到内存中,就需要分批来处理。

常见的做法有两种:

分批加载到内存处理

1.读取最大内存可以容纳的记录创建哈希表 构建输入 生成哈希表;

2.遍历 探测输入 对这部分哈希表进行一次全量探测;

3.清理掉哈希表重新进行这个流程,直至全部处理完成。

这种方式会导致探测输入全表被扫描多次。

写到文件处理

1.当在构建哈希表阶段内存用完时,服务器将会把剩余的构建输入写到磁盘上的许多小文件中,小文件块经过计算可以全部被读入内存并创建哈希表(避免文件块太大后续无法加载到内存还需要再次分隔);

2.在探测阶段,由于探测行可能与写入磁盘的构建输入的某行匹配,所以也需要将探测输入写入到磁盘中;

3.探测阶段完成后,从磁盘读取块文件并加载到内存散列表中,再从探测输入读取响应的块文件并探测匹配项;

4.处理完后,移动到下一对块文件,直至全部处理完成。

MySQL 中的哈希连接实现

MySQL 会选择两个输入中较小的一个作为构建输入(以字节计算),在内存足够的情况下将构建输入加载到内存处理,不够的情况下使用写入文件的方式处理。

可以使用 join_buffer_size 系统变量控制 哈希连接 的内存使用,哈希连接 使用的内存不能超过这个数量,当超过这个数量时,MySQL 将使用文件来处理。

如果内存超过 join_buffer_size,并且文件超过 open_files_limit ,执行可能失败。

可以使用如下两个解决方案:

● 增大 join_buffer_size 来避免 哈希连接 溢出到磁盘

● 增大 open_files_limit

MySQL 什么情况下会使用哈希连接?

在 MySQL 8.0.18 版本中,如果使用一个或多个等连接条件将表连接在一起,并且没有可用于连接条件的索引,将使用哈希连接。如果索引可用,MySQL 倾向于使用索引查找来支持嵌套循环。

默认情况下,MySQL 会尽可能使用哈希连接 ,可以通过以下两种方式启用或关闭:

● 设置全局或 session 变量 (hash_join = on or hash_join = off);

SET optimizer_switch="hash_join=off";

● 使用 hints (HASH_JOIN or NO_HASH_JOIN)。

我们将使用以下查询作为示例:

EXPLAIN FORMAT = treeSELECT  city.name AS city_name,  province.name AS province_nameFROM  city  JOIN province    ON city.province_id = province.province_id;

输出为:

| -> Inner hash join (city.province_id = province.province_id)  (cost=1333.82 rows=1329)    -> Table scan on city  (cost=0.14 rows=391)    -> Hash        -> Table scan on province  (cost=3.65 rows=34)

哈希连接 也可以用到多个 join 的查询中,只要存在等值连接,就可以使用哈希连接。

例如以下查询:

EXPLAIN FORMAT= TREESELECT  city.name AS city_name,  province.name AS province_name,  country.name AS country_nameFROM  city  JOIN province    ON city.province_id = province.province_id    AND city.id < 50  JOIN country    ON province.province_id = country.id

输出为:

| -> Inner hash join (city.province_id = country.id)  (cost=23.27 rows=2)    -> Filter: (city.id < 50)  (cost=5.32 rows=5)        -> Index range scan on city using PRIMARY  (cost=5.32 rows=49)    -> Hash        -> Inner hash join (province.province_id = country.id)  (cost=4.00 rows=3)-> Table scan on province  (cost=0.59 rows=34)-> Hash    -> Table scan on country  (cost=0.35 rows=1)

哈希连接也同样适用于 「笛卡尔积」,即没有指定查询条件,如下:

EXPLAIN FORMAT= TREESELECT  *FROM  city  JOIN province;

输出为:

| -> Inner hash join  (cost=1333.82 rows=13294)    -> Table scan on city  (cost=1.17 rows=391)    -> Hash        -> Table scan on province  (cost=3.65 rows=34)

MySQL 什么情况下不会使用哈希连接?

1.目前 MySQL 哈希连接只支持内连接,反连接、半连接和外连接仍然使用块嵌套循环执行。

2.如果索引可用,MySQL 会更倾向于使用索引查找来支持嵌套循环;

3.当不存在等值查询时,会使用嵌套循环。

如下:

EXPLAIN FORMAT=TREESELECT  *FROM  city  JOIN province    ON city.province_id < province.province_id;

输出为:

| <not executable by iterator executor>

如何查看语句执行是否使用哈希连接?

EXPLAIN FORMAT= TREE 在 MySQL 8.0.16 及之后的版本可以使用,TREE 提供了类似于树的输出,对查询处理的描述比传统格式更加精确,它是唯一显示 哈希连接 用法的格式。

除此之外,也可以使用 EXPLAIN ANALYZE 查看 哈希连接 信息。

<hr/> 以上基于 MySQL community Server 8.0.18。

以上就是数据库哈希连接详解(MySQL新特性)的详细内容,更多请关注其它相关文章!


  • 上一条:
    浅谈MySQL数据库多表查询
    下一条:
    如何利用xtrabackup备份mysql数据库
  • 昵称:

    邮箱:

    1条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客