09丨子查询:子查询的种类都有哪些,如何提高子查询的性能?
09丨子查询:子查询的种类都有哪些,如何提高子查询的性能?
讲述:陈旸
时长11:44大小10.71M
什么是关联子查询,什么是非关联子查询
EXISTS 子查询
集合比较子查询
将子查询作为计算字段
总结
赞 26
提建议
精选留言(192)
- 看,有只猪2019-07-01IN表是外边和内表进行hash连接,是先执行子查询。 EXISTS是对外表进行循环,然后在内表进行查询。 因此如果外表数据量大,则用IN,如果外表数据量小,也用EXISTS。 IN有一个缺陷是不能判断NULL,因此如果字段存在NULL值,则会出现返回,因为最好使用NOT EXISTS。
作者回复: 总结的不错
共 11 条评论171 - humor2019-07-03exist和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
共 19 条评论88 - Sam2019-07-01not in是先执行子查询,得到一个结果集,将结果集代入外层谓词条件执行主查询,子查询只需要执行一次; not exists是先从主查询中取得一条数据,再代入到子查询中,执行一次子查询,判断子查询是否能返回结果,主查询有多少条数据,子查询就要执行多少次。
作者回复: 总结的不错
共 2 条评论54 - hsj2019-09-29SELECT * 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) 所以小表驱动大表能够大幅度提高执行速度展开
作者回复: 总结的不错!
共 7 条评论36 - Hero2019-07-011. 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 总结的不错
共 9 条评论32 - Serendipity2019-09-01我怎么感觉简单的地方讲的比较多,难的地方一笔带过了?看的好懵逼。
作者回复: 后面有些内容是和SQL优化相关的,前面相对基础
共 5 条评论27 - Chuan2019-11-01老师,听完这节课,有几个问题,烦请解惑: 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+树的深度)
共 2 条评论13 - OperaX2019-07-07SELECT 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代码结构清晰
共 2 条评论12 - Goal2019-07-01# 使用exists SELECT player_name,player_id,team_id from player WHERE EXISTS (SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id and score >20) # 使用 in SELECT player_name,player_id,team_id from player WHERE player_id IN (SELECT player_id FROM player_score WHERE score >20) 使用:join 语句 SELECT p.player_name,p.player_id,p.team_id,t.score from player AS p JOIN player_score as t WHERE p.player_id = t.player_id and t.score >20展开共 4 条评论10
- 小星星2019-07-09SELECT 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条记录
共 4 条评论8 - 华夏2019-07-01SELECT player_id, team_id, player_name FROM player WHERE player_id in (SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id); 老师,文稿中这句的WHERE player.player_id = player_score.player_id可以不要了哈。6
- 佚花2019-07-01这么说吧,我在银行遇到过两张表1700w的表,我要对比他们的差值。用in没查出来,就是查很久还报错了,用了exsit用了40s 一张1700w,一张100个值,in是一分钟,exsit是0.1s
作者回复: 佚花同学很好的分享
共 2 条评论6 - Liam2019-07-01老师您好,关于exist和in的差别,总结和举例的不符吧?主表大于从表不应该是使用in更好吗
作者回复: 当主表A大于从表B时,是使用IN子查询更好
共 5 条评论6 - OperaX2019-07-07实际工作中没用到果any all。什么样的情况下会可能用到呢?老师举的例子的话,直接比较最大值或者最小值就好了吧
作者回复: any all 通常是可以比较最大值或者最小值,两种不同的写法
5 - Mr.H2019-07-01最后的总结in和exist写反了吧
作者回复: 当主表A大于从表B时,使用IN子查询效率更高,相反主表A小于从表B时,使用EXISTS子查询效率更高
5 - 张驰皓2019-12-21SELECT player_id, team_id, player_name FROM player WHERE player_id in (SELECT player_id FROM player_score WHERE player.player_id = player_score.player_id) 这段代码里,子查询里 where 部分删去后运行结果与此前一致,是否说明此 where 语句是无意义的?展开
作者回复: 是因为这些player在player_score中都有记录,player这张表的数据量有些少,如果数据量大的话,没有在player_score(即没有打过比赛的球员)是不会显示出来的
4 - 峻铭2019-09-03前提条件: 1、我理解的场均得分大于20,第一场得了40分,第二场得了2分,场均为21分满足条件 2、一场比赛中,球员可以出现多次 解析思路,先得出球员在每场比赛中的总分数,然后对球员分组,计算球员在所参加比赛中的平均数 SELECT t2.player_id, t2.player_name, t2.team_id, t3.v FROM player AS t2 JOIN ( SELECT t1.player_id, avg( t1.total ) AS v FROM ( SELECT player_id, sum( score ) AS total FROM player_score WHERE game_id IN ( SELECT game_id FROM player_score GROUP BY game_id ) GROUP BY player_id #对球员分组,计算在每场比赛中的总分数 ) AS t1 GROUP BY t1.player_id #对球员分组,计算所参加比赛的平均数 HAVING v > 20 #场均得分大于20 ) AS t3 ON t2.player_id = t3.player_id; +-----------+------------------+---------+---------+ | player_id | player_name | team_id | v | +-----------+------------------+---------+---------+ | 10001 | 韦恩-艾灵顿 | 1001 | 26.0000 | | 10002 | 雷吉-杰克逊 | 1001 | 22.0000 | +-----------+------------------+---------+---------+展开
作者回复: 整理和分析的不错
共 3 条评论3 - 华夏2019-07-01SELECT player_id, player_name, team_id FROM player AS a WHERE (SELECT score FROM player_score AS b WHERE a.player_id = b.player_id) > 20; +-----------+------------------+---------+ | player_id | player_name | team_id | +-----------+------------------+---------+ | 10001 | 韦恩-艾灵顿 | 1001 | | 10002 | 雷吉-杰克逊 | 1001 | +-----------+------------------+---------+ 2 rows in set (0.01 sec)展开
作者回复: 需要注意下是场均得分>20
3 - Cary2019-07-01in 和 exist 上面和最后总结的好像不一致3
- 苏籍2019-07-02WHERE a.team_id = b.team_id 想确定一下这个条件 是在两个相同的表做笛卡尔积后 做了啥操作,能帮梳理一下思路吗
作者回复: for player1 in a表 for player2 in b表 根据player2.team_id=player1.team_id 进行筛选,然后求解avg(player2.height)
共 2 条评论2