子查询类似递归函数,虽然代码易于实现,但是执行效率低下。表连接适合看更多表数据,子查询灵活多变,适合作为查询的筛选条件。
我们曾在《MySQL 子查询》介绍过表连接,它可以被子查询替换,而想要通过表连接替换子查询却不是100%能够实现!下面我将介绍哪些子查询可以转为表连接:
在查询优化中,对于可被重写的子查询,应优先考量其与表连接在性能上的等效性。若子查询存在显著性能瓶颈,将其重构为表连接是首选的优化策略之一,并通过执行计划对比验证优化效果。
举个例子:
准备一个子查询。有两张表,一张学生表,有id、name、gender三个字段,有一张成绩表,有id、grade、summary三个字段;
现在我需要查找总评是'优秀'的学生,我会这样做:
SELECT * FROM studentsTab WHERE id IN (SELECT id FROM gradeTab WHERE summary = '优秀');
如果改成一个表连接呢?
SELECT s.* FROM studentsTab INNER JOIN gradeTab g ON s.id = g.id WHERE g.summary = '优秀';
我们发现,如果子查询是这种形式:
SELECT * FROM table1 WHERE column1a IN (SELECT column2a FROM table2 WHERE column2b = value);
表连接可以写成:
SELECT table1.* FROM table1 INNER JOIN table2 ON table1.column1a = table2.column2a WHERE table2.column2b = value;
如果在存在一对多关系的情况下,等价的子查询与关联查询可能返回不同数量的行,其根本原因在于两者处理table2中重复值的方式不同。此时需要在表查询时使用SELECT DISTINCT代替SELECT。
如果我们想查询非匹配值呢,需要查找总评不是'优秀'的学生该怎么办?
可以这样写:
SELECT * FROM studentsTab WHERE id NOT IN (SELECT id FROM gradeTab WHERE summary = '优秀');
其对应的表连接可以写成:
SELECT s.* FROM studentsTab s LEFT JOIN gradeTab g ON s.id = g.id AND g.summary = '优秀' WHERE g.id IS NULL;
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程