在sql中使用join可能遇到的问题

以前看《阿里开发手册》时,就注意到这样一点“超过三个表禁止join。需要join的字段,数据类型必须绝对一致。”

那么,为什么很多人都反对使用join?在sql中使用join可能遇到什么问题?

参考:https://huoding.com/2016/12/18/577

 

一、join的性能差吗?

一直以来似乎流传着这样一种结论:之所以不应该使用join,是因为join的性能差。这导致很多人被吓得不敢在sql中用join。但是,为什么join的性能差呢?似乎又很少人去论证…

我们举个例子来讨论join的性能:查询最新的十篇帖子和对应的用户信息。

(1)使用join

如果使用join,那么sql如下:

只需要这样一句sql就搞定了。

(2)不使用join

如果不使用join,那就只好拆成两条sql:

首先从posts表中查询出最新的十篇帖子的信息,然后把这些信息中的user_id属性抽取出来,再根据每个user_id到users表中查询出用户的信息,再把帖子信息和对应的用户信息组合起来返回。

(3)对比分析

可以发现,如果禁止使用join,整个业务流程就变得非常复杂,简直就是一种折磨。

现在我们对照阿里的“超过三个表禁止join”(并不是在任何情况下都禁止使用join),发现当前需求只涉及posts和users两个表,没有使用限制。

个人认为,这个规约不会破坏简单功能的实现,符合三表以下的情况都可以使用join(如果在不同的DB实例中就当我没说…)。

刚才我们讨论了业务流程问题,还有个最为关键的性能问题(就算业务流程复杂,只要优化了性能,那么还算说得过去)。那么请问各位读者,你真的觉得在这里使用join会比不使用join慢吗…显然不可能啊,反而是用join会快很多。

综上,“各种不建议使用join/禁止使用join”不是因为“join的性能差”,而是因为别的什么原因。

(这里我个人觉得有点问题:简单业务确实是join比较快,但是如果需要join一大堆表,在性能上依然不容乐观。如果代码层面可以使用缓存、特定接口等一系列解决方案,性能“也许”可以比join更好,需要具体情况具体分析,具体可以参考文末的文章)

二、垂直拆分时的问题

(1)垂直拆分

先从一张图开始了解垂直拆分的概念:

1

一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,拆分到不同的数据库,从而将数据(或者说压力)分担到不同的库。

优点是:拆分后业务清晰,拆分规则明确。系统之间整合或扩展容易。数据维护简单。

相对的,缺点是事务处理变得更复杂(一般的事务无法跨库,需要在自己的应用中做事务)。不能跨DB使用join(不在同一DB中怎么使用join…)。有些不复杂的业务无法充分利用DB性能(一些简单的、压力不大的、很容易使用join实现的业务无法发挥优势)。

(其实就是我们平时所说的分库啦)

(2)垂直拆分时可能需要大量改写带有join的sql

回头看看上面的例子,在执行posts join users的时候,实际上相当于做出了一个承诺:posts和users两个结婚的表将永远住在同一个DB实例上,以后无论贫穷还是富有,疾病还是健康,永不分离。

不过实际上,随着项目的发展(特别是现在提倡的微服务化,一些功能会分得比较细),很可能会出现posts和users两个表不得不离婚的情况,结果它们会被划分到不同 DB实例。

一旦出现此类情况,那么当初使用join的地方将不得不大量改写。相比之下,不使用join的地方受到的影响会比较小(更稳定,利于拆分,代价就是代码层面更复杂)。

我们再回顾阿里的“超过三个表禁止join”,原因应该是:“如果操作涉及超过三个表,那么表拆分的可能性将变大,使用join的sql语句很可能需要重写,重构时更加复杂”。基于以上原因,禁止使用join。

三、如何判断是否适合使用join?

如果相关的表以后有独立部署的可能性,那么就要考虑避免使用join,否则用join也无妨。

当然,有人会找出一些使用join后效率奇差的例子,不过这样的问题一来可能是索引不佳,二来可能是特殊情况,用不用join都会有类似的问题(只要使用的时候留意即可)。

四、总结

总的来说,“禁止使用join”是出于“需要拆分业务的考虑”,而不是出于“join性能差的顾虑”。是否在sql中使用join,还是需要具体情况具体分析。

最近在知乎上看到了一个回答,我觉得讲得非常好:

https://www.zhihu.com/question/56236190/answer/161571374

可以帮助理解这个问题。

发表评论

电子邮件地址不会被公开。 必填项已用*标注