在一开始,我先讲述一下什么叫做 虚拟表吧,因为这是我自己一时兴起建立的名词。
我们平常使用LEFT JOIN 查询的SQL语句是什么样的呢?一般都是下面的这种情况吧…
SELECT * FROM a LEFT JOIN b ON a.id = b.a_id
大致都是上面的情况,我们使用 LEFT JOIN 的对象大致都是一个数据表。但是,有些情况下却不是如此,
SELECT * FROM a LEFT JOIN ( SELECT * FROM b ) b ON a.id = b.a_id
SELECT * FROM B 本是一个结果集合,确也可以单做集合来当成一个虚拟表来进行左连接,这种把数据查询集合模拟成表的操作,我这里暂时命名其为虚拟表。
(当然这种虚拟表的使用环境并不仅仅只是在LEFT JOIN 之中,任何可以引申到表的这个概念的情况都是可以使用这样的方法来进行代替)
下面,我们就跟着实际的问题情况,来进行分析对应的数据吧。
问题环境是如此,需要对某些数据进行各种类型的统计的操作。但是,由于没有“统计表”的这个概念,因此,我们就需要进行一个复杂的数据叠加操作。
但是,这个代码本就是祖传代码。外加上之前的开发者将9个数据统计逻辑,写入在一个查询语句之内。然后每一个数据查询逻辑都使用了** “左连接” **。因此,这样的情况就导致了,一次的查询需要5秒左右操作才可以计算出结果。为了初步解决问题,过去的开发者在其之上加入了Redis缓存来实现上线。
首先,我进行代码的分析,主要发现的问题便是其中的左连接语句大致上的逻辑为以下
SELECT * FROM a
LEFT JOIN ( SELECT * FROM b ) b ON a.id = b.a_id #左连接部分
WHERE a.id =xxxx #条件查询语句
便是连接语句之中的条件语句为空,导致的了问题的发生。
原作者本来的目的意图为:在MYSQL 查询完了 a 表之后,再b表之中所有条件符合 a.id = b.a_id 的数据。最后合并结果输出。
但是,在LEFT JOIN 的作用之下,却是a表查a表的,b表先执行完sql语句之后根据 ON 条件合并。
导致需要查询整张b表,导致的问题发生。
我们的解决方案的道理很简单,减少 LEFT JOIN 之中的数据量大小就好。这样也是为什么常说LEFT JOIN 需要连接数据量表比较小的数据。但是若业务需要,两张表的数据量大小也说不好谁多谁少,或者祖传代码,不能随表乱改数据的输出结构。那么我们就需要在LEFT JOIN 语句之中加上查询条件
当然道理很简单,难的却是如何去实现。实际的优化方案应该,由大家所面临的的实际问题来进行判断,但是在这里可以给大家两种更改的方案建议。记住,仅仅只是建议:
当代码结构简单,我们可以轻松的加上WHERE条件来进行操作,就比如上面的代码
SELECT * FROM a
LEFT JOIN ( SELECT * FROM b WHERE b.a_id IN ( SELECT * FROM a.id = xxxx) ) b ON a.id = b.a_id
#左连接部分
WHERE a.id =xxxx #条件查询语句
简单的说,便是将外部的查询代码再重新添加在这里罢了。虽然,这样的操作,在看来十分的可笑。但是在逻辑之上却是比较轻松的解决问题。由于查询条件的一致,LEFT JOIN 查询出来的数据,也正是 a表所需要的的,并不会保证数据查询的资源浪费。
PS: 看到这里,大家可能会问,这样的操作好处在哪里呢?改成下面不好嘛
SELECT * FROM a , b WHERE a.id = b.a_id #轻轻松松解决问题
的确在LEFT JOIN 内部语句逻辑简单的的时候,如此的操作的确轻松异常。但是个人认为,轻松仅仅是代码量。但若是LEFT JOIN 内部有 GROUP BY 分组操作,那么在上面的代码基础之上,我们需要怎么样的更改呢?而且最重要的便是输出结果的不一致,在大量祖传代码存在的同时,很少的情况能如此自由的更改结果。