mysql8为何取消嵌套循环

mysql8为何取消嵌套循环,第1张

找到了更好的连接方式。在mysql8.0.20开始,删除了对块嵌套循环的支持,服务器找到了更好的连接方式,在以前使用块嵌套循环的地方使用散列连接,要比嵌套循环更方便更有效。MySQL是一个关系型数据库管理系统,由瑞典MySQLAB公司开发,属于Oracle旗下产品。

mysql8以前 的 join 算法只有 nested loop 这一种,在 MySQL8 中推出了一种新的算法 hash join,比 nested loop 更加高效。mysql8中的部分NLJ算法已经取消,hash join 是它的的替代方案。像属于NLJ的BNLJ、SNLJ都会被Hash join替代!不过基于索引的INLJ算法还是存在的,所以实际使用中可以对比下INLJ和Hash Join的查询性能然后做出选择。

个人觉得mysql8这个hash join也只能算是一个锦上添花的功能,顶多是代替了没有加索引时默认走的BNLJ算法,提高了join的性能下限。说白了就是给不懂加索引的mysql新用户提高下join性能。其实也不绝对,不过我有做 INLJ和Hash Join 对比实验,Hash Join 很有可能比需要在内部表建立索引的INLJ算法性能要好!毕竟当INLJ需要回表查的时候性能会大幅度下降,这时候Hash Join绝对值得一试的,当然具体两者之间的选择还请自己实际测试下。

创建user和book表

可以看看下列语句的执行计划,Extra 出现了 Using join buffer (hash join) 说明该语句使用到了hash join。这里还使用了 IGNORE index(index_user_id)禁用索引,不然使用的是INLJ。

那么,使用Hash Join会分为下面2个阶段:

1、build 构建阶段:从参与join的2个表中选一个,选择占空间小的那个表,不是行数少的,这里假设选择了 user 表。对 user表中每行的 join 字段值进行 hash(a.id ) 计算后放入内存中 hash table 的相应位置。所有行都存放到 hash table 之后,构建阶段完成。

溢出到磁盘在构建阶段过程中,如果内存满了,会把表中剩余数据写到磁盘上。不会只写入一个文件,会分成多个块文件。

2、probe 探测阶段:对 book 表中每行中的 join 字段的值进行 hash 计算:hash(b.user_id) 拿着计算结果到内存 hash table 中进行查找匹配,找到一行就发给 client。这样就完成了整个 join *** 作,每个表只扫描一次就可以了,扫描匹配时间也是恒定的,非常高效。

散列连接的内存使用可以使用join_buffer_size系统变量来控制;散列连接使用的内存不能超过这个数量。当散列连接所需的内存超过可用的数量时,MySQL通过使用磁盘上的文件来处理这个问题(溢出到磁盘)。

如果发生这种情况,您应该知道,如果散列连接无法容纳在内存中,并且它创建的文件超过了为open_files_limit设置的数量,则连接可能不会成功。

为避免此类问题,请执行以下任一更改:

1、增加join_buffer_size,以便哈希连接不会溢出到磁盘。

在MySQL 8.0.19及更高版本中, 设置 optimizer_switch 变量值 hash_join=on or hash_join=off 的方式已经失效了

2、增加open_files_limit。若数据量实在太大内存无法申请更大的join_buffer,就只能溢出到磁盘上了。我们可以增加open_files_limit,防止创建的文件超过了为open_files_limit设置的数量而join失败。

必须使用format=tree(8.0.16的新特性)才能查看hash join的执行计划:

创建几张测试表

从MySQL 8.0.18开始,MySQL对每个连接都有一个等连接条件的任何查询都使用散列连接,并且没有可应用于任何连接条件的索引,例如:

在MySQL 8.0.20之前,如果任何一对连接的表没有至少一个等连接条件,就不能使用Hash Join,并且使用了较慢的BNLJ。而 在MySQL 8.0.20和更高版本中,hash join可以用于未包含等值连接条件的查询

甚至是笛卡尔积的join

Semijoin也行

还有 antijoin

版本:MySql 8.0.20

如果设置密码 123456

在修改密码时遇到 Your password does not satisfy the current policy requirements

如何解决?

方案一:

设置一个符合规则的密码:Abc123...

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Abc123...'

方案二:

如果你就想设置 密码为 123456,怎么办?

a、先设置为符合规范的密码: Abc123...

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Abc123...'

b、然后查看当前默认规则:SHOW VARIABLES LIKE 'validate_password%'

c、修改校验密码策略等级

set global validate_password.policy=LOW

d、设置密码长度至少为 6

set global validate_password.length=6

e、最后设置 123456

ALTER USER 'root'@'localhost' IDENTIFIED BY '123456'

就可以了


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/7665482.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-08
下一篇 2023-04-08

发表评论

登录后才能评论

评论列表(0条)

保存