mysql 子查询怎么写_MySQL中两种子查询的写法

MySQL的测试环境

49252e455672944ba07c86a4e88bc383.png

测试表如下

create table test_table2

(

id int auto_increment primary key,

pay_id int,

pay_time datetime,

other_col varchar(100)

)

建一个存储过程插入测试数据,测试数据的特点是pay_id可重复,这里在存储过程处理成,循环插入300W条数据的过程中,每隔100条数据插入一条重复的pay_id,时间字段在一定范围内随机

CREATE DEFINER=`root`@`%` PROCEDURE `test_insert`(IN `loopcount` INT)

LANGUAGE SQLNOT DETERMINISTICCONTAINS SQL

SQL SECURITY DEFINER

COMMENT ''BEGINdeclare cnt int;set cnt = 0;while cnt< loopcount doinsert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());if (cnt mod 100 = 0) theninsert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());end if;set cnt = cnt + 1; end while;END

执行 call test_insert(3000000); 插入303000行数据

7a07f7fa626c600545d8f448c36400f8.png

两种子查询的写法

查询大概的意思是查询某个时间段之内的业务Id大于1的数据,于是就出现两种写法。

第一种写法如下:IN子查询中是某段时间内业务统计行数大于1的业务Id,外层按照IN子查询的结果进行查询,业务Id的列pay_id上有索引,逻辑也比较简单,

这种写法,在数据量大的时候确实效率比较低,用不到索引

select * from test_table2 force index(idx_pay_id)where pay_id in (  select pay_id from test_table2

where pay_time>="2016-06-01 00:00:00"

AND pay_time<="2017-07-03 12:59:59"

group by pay_id

having count(pay_id) > 1);

执行结果:2.23秒

8ed684e63dd2a125c6e1e9347a3c4b25.png

第二种写法,与子查询进行join关联,这种写法相当于上面的IN子查询写法,下面测试发现,效率确实有不少的提高

select tpp1.* from test_table2 tpp1,

( select pay_id

from test_table2

WHERE pay_time>="2016-07-01 00:00:00"

AND pay_time<="2017-07-03 12:59:59"

group by pay_id

having count(pay_id) > 1) tpp2

where tpp1.pay_id=tpp2.pay_id

执行结果:0.48秒

e89bd3cfe6abacf0330f63bddfdefcdc.png

In子查询的执行计划,发现外层查询是一个全表扫描的方式,没有用到pay_id上的索引

39c58ef100e85be72cd45e3422e9d2cd.png

join自查的执行计划,外层(tpp1别名的查询)是用到pay_id上的索引的。

ad2776c759ed240286b63eb1f8f0e88f.png

后面想对第一种查询方式使用强制索引,虽然是不报错的,但是发现根本没用

445364fdc2a82a9d08f4d5eb52fd58dc.png

如果子查询是直接的值,则是可以正常使用索引的。

0f750e3cfee543d2be4db55a6f731c99.png

可见MySQL对IN子查询的支持,做的确实不怎么样。

另外:加一个使用临时表的情况,虽然比不少join方式查询的,但是也比直接使用IN子查询效率要高,这种情况下,也是可以使用到索引的,不过这种简单的情况,是没有必要使用临时表的。

e7bca384662810726ff00febf497edaa.png

下面是类似案例在sqlserver 2014中的测试,几万完全一样的测试表结构和数量,可见这种情况下,两种写法,在SQL Server中可以认为是完全一样的(执行计划+效率),这一点SQL Server要比MySQL强不少

3b1dd32b95e04a25617402dfd2edc0da.png

下面是sqlserver中的测试环境脚本。

create table test_table2

(

id int identity(1,1) primary key,

pay_id int,

pay_time datetime,

other_col varchar(100)

)begin trandeclare @i int = 0while @i<300000begininsert into test_table2 values (@i,getdate()-rand()*300,newid());

if(@i%1000=0)begininsert into test_table2 values (@i,getdate()-rand()*300,newid());endset @i = @i + 1endCOMMITGOcreate index idx_pay_id on test_table2(pay_id);

create index idx_time on test_table2(pay_time);GOselect * from test_table2

where pay_id in (select pay_id from test_table2 where pay_time>='2017-01-21 00:00:00' AND pay_time<='2017-07-03 12:59:59' group by pay_id having count(pay_id) > 1);

select tpp1.* from test_table2 tpp1,

( select pay_id

from test_table2

WHERE pay_time>='2017-01-21 00:00:00' AND pay_time<='2017-07-30 12:59:59'

group by pay_id having

count(pay_id) > 1) tpp2

where tpp1.pay_id=tpp2.pay_id

总结:在MySQL数据中,截止5.7.18版本,对IN子查询,仍要慎用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
### 回答1: MySQL递归查询语句可以使用WITH语句来实现,具体的写法如下:WITH RECURSIVE 语句 (参数列表) AS (初始查询) UNION [ALL] SELECT 语句 (参数列表) FROM 表名称 [WHERE 条件] ) SELECT 语句 (参数列表) FROM 表名称 [WHERE 条件] 。 ### 回答2: 在MySQL,可以使用递归查询语句来处理具有层级关系的数据。 MySQL没有内置的递归查询语句,但可以使用存储过程来模拟递归查询。以下是一个简单的示例来说明如何实现递归查询: 首先,创建一个存储过程,定义一个临时表来存储查询结果: ``` CREATE TEMPORARY TABLE temp_table ( id INT, name VARCHAR(255), parent_id INT ); ``` 接下来,创建一个存储过程来执行递归查询: ``` DELIMITER $$ CREATE PROCEDURE recursive_query(IN p_id INT) BEGIN -- 插入初始数据 INSERT INTO temp_table(id, name, parent_id) SELECT id, name, parent_id FROM your_table WHERE parent_id = p_id; -- 递归查询 WHILE ROW_COUNT() > 0 DO INSERT INTO temp_table(id, name, parent_id) SELECT your_table.id, your_table.name, your_table.parent_id FROM your_table JOIN temp_table ON your_table.parent_id = temp_table.id; END WHILE; -- 输出查询结果 SELECT * FROM temp_table; -- 清空临时表 TRUNCATE TABLE temp_table; END $$ DELIMITER ; ``` 在上面的存储过程,首先会将初始节点插入到临时表,然后通过循环嵌套查询,将所有子节点逐层插入到临时表,直到没有更多的子节点为止。最后,通过查询临时表来获取递归查询结果。 要调用这个存储过程并执行递归查询,可以使用以下语句: ``` CALL recursive_query(0); -- 传入初始节点的id ``` 上述示例的递归查询是一个简单的示例,实际应用可能需要根据具体的场景进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值