欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > 49 mysql 子查询 加 group by 产生的奇怪现象

49 mysql 子查询 加 group by 产生的奇怪现象

2024/10/24 5:19:26 来源:https://blog.csdn.net/u011039332/article/details/131991086  浏览:    关键词:49 mysql 子查询 加 group by 产生的奇怪现象

前言

这里要提到的是一个 之前碰到的一个 很令人诧异的查询, 主要是 和 group 查询有关系 

查询如下, 按照常规理解, “select id from t_user_02 where name = 'jerry' group by age

” 会返回 两条数据, 然后 整个查询 会查询出两条数据

但是 结果很令人差异, 查询出了 四条数据

select *, 2, 2, 2 from t_user where id in (
select id from t_user_02 where name = 'jerry' group by age
);

 

测试数据表如下, t_user 和 t_user_02 完全一样, t_user_02 是由 t_user 复制而来 

CREATE TABLE `t_user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`name` varchar(24) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8

 

测试数据如下 

9069512a1a3038c9530480fa1c04bffb.png

 

查询结果如下 

1ff0289983ba2d33eb121377d2d865bb.png 

 

 

正常实现业务的 sql 执行

对应的能够正确 实现业务的查询如下

select *, 2, 2, 2 from t_user where id in (
select max(id) from t_user_02 where name = 'jerry' group by age
);

 

这里整个流程 会分为 几个部分

1.执行 ” select age, max(id) from t_user_02 where name = 'jerry' group by age” 将结果输入临时表 tmp1
2.从 tmp1 中抽取 max(id) 字段, 将结果 汇总成为 tmp2 
3.执行 “select *, 2, 2, 2 from t_user where id in $idList” 的条件查询 
4.输出 “select *, 2, 2, 2 from t_user where id in $idList” 的执行结果 

 

这里查询的主表是 t_user, 然后 这里是来 判断 id in ($idList) 的条件的地方 触发了

“select max(id) from t_user_02 where name = 'jerry' group by age” 的查询, 以及条件处理 

3b43c8f4c022a6c6d68756e68d0549b7.png

 

 

子查询的执行1 

子查询这边的执行 具体分成了两个阶段 

第一个 qup_tab 查询对应于 “select age, max(id) from t_user_02 where name = 'jerry' group by age”

第二个 qup_tab 查询对应于 “select max(id) from (select age, max(id) from t_user_02 where name = 'jerry' group by age) as tmp”

3f46586b2f65b12038bcc8c90b7bde1e.png

 

获取 max(id) 列作为 临时表2 

b87545f03fccb54fe3c6db6d5244d752.png 

查询具体的数据表 只会执行一次, 持久化到临时表 tmp1 然后 后面是查询 临时表 tmp1 将 max(id) 列输出到 临时表 tmp2  

54e504534f17e1192049c44819b69757.png 

查询 t_user_02 的 “where name = 'jerry'”

923dcad274eb1e3c411e74d2870c5d36.png 

执行 group by 和 merge 处理如下, 对应于 “select max(id)” + “group by age”

67acccebc4a70ad260db5d9f1bd2839b.png 

这里是具体的数据调整的地方 

ba97e181e1c60a88cb76cd1699f6c70d.png 

数据更新 内容大致如下, 原来 age 121 对应的 max(id) 为 3, 如今更新为 5

最终 临时表中会有两条记录 ”age 121 -> max(id) 5”, ”age 21 -> max(id) 6”

d8965794c19acc96c0a9228c1beb8d6d.png

 

临时表 tmp1 的名字 

4a4773708ade8e45a0292a247b42ae52.png 

 

子查询的执行2

从 临时表 tmp1 中迭代记录, 这里是基于 上面的 tmp1 的查询结果进行迭代 

79df2f2a72de620c50cb08bfb17cd155.png

 

将 “id 6” 输出到 临时表 tmp2

8ee3fc6ae27d6d8a572310f8d8f25299.png 

将 “id 5” 输出到 临时表 tmp2

c210f04a5ea4c60966c66fdcea272c2d.png 

 

主表的条件判断

这边第一个操作数为 t_user.id, 右侧操作数为 上面子查询临时表 

1992f56efb978d45f6dd08a8098858e5.png

 

显示根据 待查主键 1, 查询临时表 

如果查询到, 则返回 true, 否则 返回 false 

2e16b95aa9b4ab4e3a0c1a97cde8387c.png

 

在临时表中查询到了 id 为 5

7ed99b98315b447be7f02db7008149f3.png 

下游的 比较 t_user 中当前行的 id 和 临时表中查询到的 id 的比较, 判断 是否相同

cdcaeff4d4e8825d4799b879d897da65.png 

 

主表中匹配到的结果的输出 

这里是 id 为 5 的记录的输出 

a32f8abc48a5d1dbcd13960bce675102.png

 

这里是 id 为 6 的记录的输出 

c1ed5426e4792528c07b2311ce984c33.png 

 

异常的 sql 执行 

我们这里的 问题sql查询如下

select *, 2, 2, 2 from t_user where id in (
select id from t_user_02 where name = 'jerry' group by age
);

 

从结果上来看 这个查询 是等价于

select *, 2, 2, 2 from t_user where id in (
select id from t_user_02 where name = 'jerry' 
);

 

主驱动表是 t_user_02, 基于 row_search_mvcc 遍历 t_user_02

a8c77208eb0ffc32ccf27a31e1024ab7.png

 

 

基于主键 来遍历 t_test, 这就是一个 典型的基于主键的 join 或者 基于主键in的子查询 

至于 为什么会有这个转换?, 这里暂不深究, 应该就是在 解析的时候进行的处理

74153fd826bb655e0a6d796548840868.png

 

 

完 

 

 

 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com