子查询类似递归函数,虽然代码易于实现,但是执行效率低下。表连接适合看更多表数据,子查询灵活多变,适合作为查询的筛选条件。

我们曾在《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;
点赞(1)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)