SELECT s.id, s.name, (SELECT count(*) FROM (SELECT subject_id, mg_userid FROM art_subject_article GROUP BY subject_id, mg_userid) t WHERE t.subject_id = s.id) AS member_num
FROM crm_subject s
ORDER BY member_num DESC;
主要关注子查询这里的改造,我们可以把这里的子查询做个分解。
首先,可以把子查询看成这样:(SELECT count(*) FROM t WHERE t.subject_id = s.id) AS member_num
,把它理解成从 t
表中查询与主表的项目产品有关的记录数量。
然后,我们再把 t
表看成 (SELECT subject_id, mg_userid FROM art_subject_article GROUP BY subject_id, mg_userid) t
,代表从文章表中查询出每个产品对应的用户ID。
最后把2个子查询,整合起来,就实现了查询项目产品表中,每个产品所对应的提交了文章的用户数量。
有没有更好的解决方案
这个折中的方案,虽然可以解决我的问题,但是,我依然想知道,有没有更好的、更标准的最佳实践。
并且此方案,也有3点不足:
改进前我们是对文章表做项目产品关联查询后再分组,改进后是对文章表做全表扫描后的分组,效率较低,在大数据下的表现不好。
优化方案是基于两层嵌套的子查询进行的,假如需要三层嵌套的子查询,此方案估计又失效了。
此优化方案较为局限,不具有普适性,不能很好的适用于各种业务场景。
所以,我将我遇到的这个问题,和解决方案分享在此,希望能帮助到有缘人,同时,也期望各位大神能够不吝赐教,分享一下最佳实践。
我沉下心来,真的去谷歌上找证据去了,还真被我找到了,你猜怎么着,此问题真的是,无解!!!
这是我搜索到的线索,其中 https://bugs.mysql.com/bug.php?id=28814 这里有个人遇到了与我一样的问题,并且在下面的评论回复中,有个人抛出了 MySQL 的官方文档,证实了此问题的存在,不是 bug,而是 MySQL 本身就不支持。
这里引用官方文档的说明:
A correlated column can be present only in the subquery's WHERE clause (and not in the SELECT list, a JOIN or ORDER BY clause, a GROUP BY list, or a HAVING clause). Nor can there be any correlated column inside a derived table in the subquery's FROM list.
注意第二句话:“子查询的 FROM 列表中的派生表内也不能有任何关联字段”。直接就给想要这么做的小伙伴们判了死刑,还真TM无解。
既然这种写法不支持,那么有没有什么替代方案?答案在这里找到了:https://dba.stackexchange.com/questions/237181/nested-subquery-giving-eror-of-unknown-column。
里面也提供了非常有价值的信息:
在 MySQL 8.0.14 版本中,优化了关联子查询不能用在 FROM 中的问题,从这个版本开始,可以使用了!!!撒花,庆祝。。。
然而悲催的是,大多数的小伙伴们,用的都是 5.6 或 5.7 的版本吧,那么这个问题的唯一解法就是:不要在 FROM 的子查询中,使用字段关联。。。
好了,都被我猜对了,我真是个天才。第一,此问题真的无解;第二,想要解决,真的只能用迂回的、折中的解决方案。
看起来,有的时候,自己就是自己的救世主,自己就是那个期盼的大神。。。