注册

为什么不建议使用多表join

前言


三年前在一家公司和开发团队的架构师合作过,一起写过代码。让我真的很难受啊,这个架构师写的代码很多逻辑都写到SQL里面,各种连表查询,SQL 非常的复杂,每次我去维护都得看好久它这个SQL逻辑。


回到最近,现在有个小伙儿班也是喜欢在SQL里面写逻辑,各种关联查询,甚至写的SQL连一万的数据连都支持不了。



都给我贡献了好几篇文章了:

完了演示的时候报错了!distinct 别乱用啊

sql 子查询的巨坑 ,80%的后端都不知道这个问题



所以我们的SQL尽量的简洁,少用多表关联查询。


为什么不建议使用多表join?


最主要的原因就是join的效率比较低
MySQL是使用了嵌套循环(Nested-Loop Join)的方式来实现关联查询的,就是要通过两层循环,用第一张表做外循环,第二张表做内循环,外循环的每一条记录跟内循环中的记录作比较,符合条件的就输出。



  1. 性能问题

    • 多表 JOIN 会增加查询的复杂性,可能导致性能下降,特别是在数据量大时。
    • 数据库需要在执行查询时处理更多的行和列,这可能导致更高的 I/O 操作和内存使用。


  2. 可读性和维护性

    • 复杂的 JOIN 查询会使 SQL 语句变得难以理解,导致维护成本增加。
    • 当查询需要频繁修改时,复杂的 JOIN 会让代码更容易出错。


  3. 索引利用率

    • 多表 JOIN 可能会导致数据库无法有效利用索引,影响查询的优化。
    • 如果 JOIN 的字段没有适当的索引,查询性能会显著下降。


  4. 锁竞争

    • 多表 JOIN 可能导致更长时间的行锁或表锁,从而增加锁竞争的可能性,影响并发性能。


  5. 数据完整性

    • 复杂的 JOIN 查询可能掩盖数据问题或不一致性,使得调试较为困难。
    • 难以确保在 JOIN 查询中返回的数据符合业务逻辑和数据完整性要求。



如何优化:



  • 分解查询:在内存中自己做关联,即先从数据库中把数据查出来之后,再次查询,然后再进行数据封装。
  • 考虑数据冗余:在某些情况下,可以考虑数据冗余来减少 JOIN 的需要。
  • 宽表:就是基于一定的join关系,把数据库中多张表的数据打平做一张大宽表,可以同步到ES或者干脆直接在数据库中直接查都可以

什么是hash join(扩展阅读)


mysql8.0 以前join查询使用Nested-Loop Join算法实现



Nested-Loop Join:嵌套循环连接,如果有2张表join的话,复杂度最高是O(n^2),3张表则是O(n^3),表中的数据量越多,JOIN的效率会呈指数级下降。



MySQL 8.0中优化了join查询,新增了 hash join算法。

Hash Join 是一种高效的联表查询算法,通常用于处理较大数据集的连接操作。下面将详细介绍 Hash Join 的原理,并通过示例图解说明其查询步骤。


Hash Join 原理


Hash Join 的基本原理是将一个表的数据构建成一个哈希表,然后利用该哈希表来查找另一个表中匹配的行。其主要分为两个阶段:



  1. 构建阶段(Build Phase):

    • 选择一个较小的表(称为构建表)来创建哈希表。
    • 根据连接条件的键值计算哈希值,并将这些键值和对应的行存储在哈希表中。


  2. 探测阶段(Probe Phase):

    • 对另一个表(称为探测表)逐行读取数据。
    • 对于探测表中的每一行,计算连接字段的哈希值,并在哈希表中查找匹配的行。
    • 如果找到匹配,则将匹配的行组合在一起,形成结果集。



Hash join 案例


假设我们有两个表:


表 A


IDName
1Alice
2Bob
3Charlie

表 B


IDAge
125
230
440

我们希望通过 ID 字段将这两个表连接起来。


步骤 1: 构建哈希表

选择表 A 作为构建表。我们将根据 ID 字段创建哈希表。



  • 对于 ID = 1,哈希值为 hash(1),存储为 {1: Alice}
  • 对于 ID = 2,哈希值为 hash(2),存储为 {2: Bob}
  • 对于 ID = 3,哈希值为 hash(3),存储为 {3: Charlie}

哈希表


{
1: Alice,
2: Bob,
3: Charlie
}

步骤 2: 探测阶段

接下来,我们对表 B 进行探测,查找与哈希表中的行匹配的行。



  • 对于 ID = 1,计算 hash(1),在哈希表中找到匹配,结果为 (1, Alice, 25)
  • 对于 ID = 2,计算 hash(2),在哈希表中找到匹配,结果为 (2, Bob, 30)
  • 对于 ID = 4,计算 hash(4),在哈希表中未找到匹配。

匹配之后做聚合就得到结果集了



这里的hash表是存在内存中的,内存是有限制的,超过阈值之后就会走 磁盘Hash join 的算法



磁盘hash join


如果驱动表中的数据量超过阈值,就会走磁盘hash join的算法。将驱动表拆分成多个哈希区(或桶),每个桶存储在磁盘上。读取磁盘上的hash桶分别加载到内存,进行探测匹配,探测完成释放当前内存桶,继续从磁盘上读取下一个hash桶进行探测匹配,直到磁盘上所有的hash桶都处理完毕。


总结


在实际开发中,尽量减少多表join查询,保持SQL的逻辑清晰,这样不仅能提高性能,还有利于维护。



感谢佬们的一键三连+关注 !!!



作者:提前退休了
来源:juejin.cn/post/7438597251487268875

0 个评论

要回复文章请先登录注册