SQL 必知必会
陈旸
清华大学计算机博士
73337 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
第一章:SQL语法基础篇 (19讲)
SQL 必知必会
15
15
1.0x
00:00/00:00
登录|注册

09丨子查询:子查询的种类都有哪些,如何提高子查询的性能?

ALL操作符
ANY操作符
IN操作符
与关联子查询一起使用
用于判断条件是否满足
只执行一次
多次执行
依赖外部查询
场均得分大于20的球员查询
NOT IN子查询和NOT EXISTS子查询效率
EXISTS子查询效率
IN子查询效率
将子查询作为计算字段
集合比较子查询
EXISTS子查询
非关联子查询
关联子查询
练习
性能优化
子查询

该思维导图由 AI 生成,仅供参考

上节课我讲到了聚集函数,以及如何对数据进行分组统计,可以说我们之前讲的内容都是围绕单个表的 SELECT 查询展开的,实际上 SQL 还允许我们进行子查询,也就是嵌套在查询中的查询。这样做的好处是可以让我们进行更复杂的查询,同时更加容易理解查询的过程。因为很多时候,我们无法直接从数据表中得到查询结果,需要从查询结果集中再次进行查询,才能得到想要的结果。这个“查询结果集”就是今天我们要讲的子查询。
通过今天的文章,我希望你可以掌握以下的内容:
子查询可以分为关联子查询和非关联子查询。我会举一个 NBA 数据库查询的例子,告诉你什么是关联子查询,什么是非关联子查询;
子查询中有一些关键词,可以方便我们对子查询的结果进行比较。比如存在性检测子查询,也就是 EXISTS 子查询,以及集合比较子查询,其中集合比较子查询关键词有 IN、SOME、 ANY 和 ALL,这些关键词在子查询中的作用是什么;
子查询也可以作为主查询的列,我们如何使用子查询作为计算字段出现在 SELECT 查询中呢?

什么是关联子查询,什么是非关联子查询

子查询虽然是一种嵌套查询的形式,不过我们依然可以依据子查询是否执行多次,从而将子查询划分为关联子查询和非关联子查询。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

SQL中的子查询是一种强大的嵌套查询形式,能够让我们进行更复杂的查询并更容易理解查询的过程。子查询分为关联子查询和非关联子查询,其中非关联子查询只执行一次,而关联子查询需要执行多次。在子查询中,可以使用关键词进行结果比较,如EXISTS子查询用于判断条件是否满足,而集合比较子查询则可以使用IN、ANY、ALL和SOME操作符进行比较。在实际应用中,需要根据表的大小和索引情况选择合适的子查询方式以提高查询效率。此外,子查询还可以作为主查询的计算字段,增强了SELECT查询的能力。通过本文,读者可以了解子查询的种类和使用方法,以及如何提高子查询的性能。 文章还讨论了在使用子查询时,如何根据字段的索引情况和表的大小选择合适的子查询方式以提高查询效率。此外,还介绍了如何使用子查询作为主查询的计算字段,以及在某些情况下使用EXISTS和IN可以得到相同的效果。最后,读者还被要求使用子查询编写SQL语句,得到场均得分大于20的球员的信息。整体而言,本文内容涵盖了SQL中子查询的基本概念、使用方法和性能优化,对读者进行了全面的指导。 通过本文,读者可以快速了解子查询的基本概念和使用方法,以及如何提高子查询的性能,同时还能够通过实际案例进行练习,加深对子查询的理解和应用能力。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《SQL 必知必会》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(195)

  • 最新
  • 精选
  • 看,有只猪
    IN表是外边和内表进行hash连接,是先执行子查询。 EXISTS是对外表进行循环,然后在内表进行查询。 因此如果外表数据量大,则用IN,如果外表数据量小,也用EXISTS。 IN有一个缺陷是不能判断NULL,因此如果字段存在NULL值,则会出现返回,因为最好使用NOT EXISTS。

    作者回复: 总结的不错

    2019-07-01
    12
    181
  • humor
    exist和in的区别这一块,感觉没有讲清楚呀,我听下来还是不太明白哪种情况应该用in,哪种情况应该用exists。选择的标准是看能否使用表的索引吗?

    作者回复: 索引是个前提,其实和选择与否 还是要看表的大小。选择的标准,你可以理解为: 小表驱动大表。这种方式下效率是最高的。比如 SELECT * FROM A WHERE cc IN (SELECT cc FROM B) SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc) 当A小于B时,用EXIST。因为EXIST的实现,相当于外表循环,实现的逻辑类似于: for i in A for j in B if j.cc == i.cc then ... 当B小于A时,用IN,因为实现的逻辑类似于: for i in B for j in A if j.cc == i.cc then ... 所以哪个表小就用哪个表来驱动,A表小 就用EXIST,B表小 就用IN

    2019-07-03
    19
    93
  • Sam
    not in是先执行子查询,得到一个结果集,将结果集代入外层谓词条件执行主查询,子查询只需要执行一次; not exists是先从主查询中取得一条数据,再代入到子查询中,执行一次子查询,判断子查询是否能返回结果,主查询有多少条数据,子查询就要执行多少次。

    作者回复: 总结的不错

    2019-07-01
    3
    55
  • hsj
    SELECT * FROM A WHERE cc IN (SELECT cc FROM B) SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc) A 表有 n 条数据,B 表有 m 条数据 两条语句的执行效率(假设都用 btree 索引) 用 in :m * log (n) 用 exists: n * log (m) 所以小表驱动大表能够大幅度提高执行速度

    作者回复: 总结的不错!

    2019-09-29
    8
    41
  • Hero
    1. SELECT player_id, team_id, player_name FROM player a WHERE EXISTS ( SELECT b.player_id FROM player_score b GROUP BY b.player_id HAVING AVG( b.score ) > 20 and a.player_id = b.player_id); 2.SELECT player_id, team_id, player_name FROM player a WHERE EXISTS ( SELECT b.player_id FROM player_score b WHERE a.player_id = b.player_id GROUP BY b.player_id HAVING AVG( b.score ) > 20); 3.SELECT player_id, team_id, player_name FROM player WHERE player_id IN ( SELECT player_id FROM player_score GROUP BY player_id HAVING AVG( score ) > 20 ); 推荐3,因为子查询只会执行一次。2比1好,因为where会先过滤数据行,然后分组,然后对分组过滤。

    作者回复: Good Job 总结的不错

    2019-07-01
    9
    33
  • Serendipity
    我怎么感觉简单的地方讲的比较多,难的地方一笔带过了?看的好懵逼。

    作者回复: 后面有些内容是和SQL优化相关的,前面相对基础

    2019-09-01
    5
    30
  • Chuan
    老师,听完这节课,有几个问题,烦请解惑: 1. in和子查询结合使用时,子查询中列的索引是否能使用?exist子查询呢? 2. 如果针对某个字段(列)添加索引,那么在查询这个字段及内容时,时间复杂度是否从O(n)变为O(1)或者O(logn)? 3. 回复中,您关于in和exist的解释,还是有点不理解。查询资料说: 两者除了驱动关系不同,in会缓存结果,但是没法使用索引;而exist不会缓存结果,每次会查数据库,但是不关心内容,只关心是否存在行记录。不知道您看法如何? 4. 您回复中,两个都是两层for循环,使得读者理解起来很困难。我觉得是不是可以这么理解: in的子查询中不能使用索引,在获得结果时耗时较久,接近O(n),所以适合内表小的场景,因为外表大但可以使用索引;exist子查询可以使用索引,同时外表都需要全遍历,所以适合内表大的场景。不过这个理解好像建立在问题1,2的答案之上。 感觉读者中不理解的蛮多的,网上资料基本上也说得不清不楚,望老师解惑。

    作者回复: IN子查询,是从表计算出来作为已知值,而EXISTS子查询是主表作为已知值传递给从表。 基于小表驱动大表的原则,主表A小 就用EXIST,从表B表小 就用IN 这里主要看能否用到索引,假设主表A有n条数据,从表B有m条数据,表A和表B中的查询字段采用B+树进行索引,那么两个子查询的执行效率: 使用 in :log (n) * m 使用 exists: n * log (m) 对于IN子查询,计算出来的结果作为已知值,就可以使得表A(n条数据)可以使用到索引,从而提升检索效率 对于EXISTS子查询,外表A作为已知值,传递给从表,可以利用从表B(m条数据)中的索引,从而提升检索效率。 (说明log 代表以2为底的对数,即B+树的深度)

    2019-11-01
    2
    15
  • OperaX
    SELECT t1.player_id, t1.player_name, t1.team_id FROM player t1 WHERE t1.player_id IN ( SELECT t2.player_id FROM player_score t2 GROUP BY t2.player_id HAVING ( AVG( t2.score ) > 20 ) )

    作者回复: 正确,而且SQL代码结构清晰

    2019-07-07
    4
    12
  • 小星星
    SELECT player_name, height, team_id FROM player AS a WHERE height > (SELECT avg(height) FROM player AS b WHERE a.team_id = b.team_id); SELECT player_name, height, team_id FROM player WHERE height > (SELECT avg(height) FROM player as b); 这两句执行的结果一样的;请问为什么需要加上a.team_id = b.team_id 有什么区别吗?

    作者回复: 第一个SQL 18条记录 第二个SQL 19条记录

    2019-07-09
    4
    8
  • 佚花
    这么说吧,我在银行遇到过两张表1700w的表,我要对比他们的差值。用in没查出来,就是查很久还报错了,用了exsit用了40s 一张1700w,一张100个值,in是一分钟,exsit是0.1s

    作者回复: 佚花同学很好的分享

    2019-07-01
    2
    7
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部