为了账号安全,请及时绑定邮箱和手机立即绑定

关联表查询是单表查询出结果后再用程序过滤还是直接用SQL语句查询最终结果

二者都有利弊吧,要从性能和易读易懂易维护各方面考虑,在什么场景下应该选哪种关联查询方式呢

正在回答

6 回答

从性能上看,关联表查询是为了应对大数据查询,减少查询的基数,灵活的配置主键等信息,提高查询的效率;

从维护上看,关联表查询从表名上更容易明白功能的分级,便于阅读和维护,并且模块划分越细,后期越容易扩展;

如果是程序开发初期,使用人群较少,访问量数据量比较少,可以使用单表查询;但是从长远上看,防止访问量飙升,数据量也飙升导致性能变慢的情况发生,应当使用关联表查询。

0 回复 有任何疑惑可以回复我~
#1

qq_双子星深蓝_0 提问者

我的问题还有一个点还没搞清楚,关联查询,有两种方式(1) ResultSet rs1 = stmt.executeQuery("select username from users where enable = 0"); ResultSet rs2 = stmt.executeQuery("select amount from orders where status = “unpay” "); for(rs1) { for(rs2) { if(rs1.username == rs2.username) { } } }
2018-12-03 回复 有任何疑惑可以回复我~
#2

qq_双子星深蓝_0 提问者

方式(2)只用一段关联语句查询ResultSet rs = stmt.executeQuery("select amount from orders where status = “unpay” and username in ("select username from users where enable = 0") "); 这两种方式如何取舍
2018-12-03 回复 有任何疑惑可以回复我~

首先,建表

create table users (
  id int unsigned not null auto_increment,
  username char not null ,
  enable tinyint not null default 0,
  primary key (id)
)ENGINE=InnoDB default charset=utf8;
alter table users
  add key key_username_enable(username, enable);

create table orders (
  id int unsigned not null auto_increment,
  username char not null ,
  status char(10) not null default "unpay",
  amount char(30) not null ,
  primary key (id)
)ENGINE=InnoDB default charset=utf8;

可以看到 我这里给 users 加的索引是 (username,enable) 而不是 (enable)。

然后当我们用 explain 去分析你给的第一条 SQL 语句的时候,

select amount 
  from orders 
where 
  status="unpay" 
    and 
  username in (select username from users where enable = 0);

就会发现 users 表上面是使用了 `key_username_enable` 的,然后这个时候,根据索引的最左匹配原则,可以知道, mysql 把 username 这个条件下推了,所以这个时候,MySQL 对于上面的 SQL 语句的执行应该是类似于以下方式

select amount 
  from orders 
where 
  status="unpay" 
    and 
  exists 
    (select orders.username from users 
      where enable=0 and users.username=orders.username);

因此把它分成两部分来理解应该是

# 1.
select amount,username from orders where status='unpay';
# 2. 
select username from users where enable=0 and username=?; #这里的?代表上一层传过来的参数

------------------------------------------------ 分割线 -------------------------------------------------------------------------------------------

好了, 其实上面的都是废话来的。

如果你是分开执行上面那两个 SQL 语句,对于 MySQL 来说,他所需要的时间是差不多的,

因为你如果是子查询,其实他也是先执行外部的找出一条数据,然后在进去子查询里面查询的,和在 Java 里面分开查询是一样的。

但是问题在于,如果是使用了子查询的话,那么你需要一次进程间通信,即 Java 给 MySQL 发送一次请求,然后 MySQL 查询完成之后返回数据。 但是如果是分开两次查询的话,那么网络通信的次数就变成了 1+(第一次结果集次),对于 MySQL 也好,Java 也好,他们的执行速度都是很快的,慢的是他们之间的通信,所以使用子查询的时候减少了他们之间通信的次数,同时需要发送的东西也少了,所以子查询会快一点。

1 回复 有任何疑惑可以回复我~
#1

qq_双子星深蓝_0 提问者

分析的很清楚,谢谢,这就延伸出另一个问题,在你的分析里用子查询能提升性能,但对于mybats框架来说mapper映射文件通常只是查询一个张表, 也就是说当一个业务需要关联多张表的时候那mybatis还是只能分两次映射分别查询orders和users之后再用程序来处理最终的结果 users.username=orders.username,这个你又怎么看呢?
2018-12-17 回复 有任何疑惑可以回复我~
#2

慕无忌2563680 回复 qq_双子星深蓝_0 提问者

不是很懂 `但对于mybatis框架来说mapper映射文件通常只是查询一个张表` 这句话,如果你在mybatis的mapper文件里面写了联表查询,那他也是一次查询而已啊。所以mapper查询一张表还是多张表还是看你怎么写啊
2018-12-18 回复 有任何疑惑可以回复我~
#3

qq_双子星深蓝_0 提问者 回复 慕无忌2563680

“但对于mybatis框架来说。。。”这句的意思是通常mybatis的写法都是一个mapper对应一张表,users.mapper, orders.mapper, users.mapper只查询users的数据,orders.mapper查询orders的数据,大部分例子都是这样,甚至慕课网上的一些项目都是在各自mapper查询出单表数据之后再用程序处理关联逻辑。这就不太清楚考量的尺度,什么情况下才考虑用一个mapper关联多表查询?
2018-12-19 回复 有任何疑惑可以回复我~
#4

慕无忌2563680 回复 qq_双子星深蓝_0 提问者

在mapper文件里面什么时候用联表查询这个问题,首先第一个就是在有明显的包含关系的时候就会用联表查询,比如说相册表和图片表这种(一个相册包含多个图片);还有一个就是在比如上面的查询结果只有其中一张表的数据;再还有一个就是比如删除、更新的时候也会使用联表查询。
2018-12-19 回复 有任何疑惑可以回复我~
#5

qq_双子星深蓝_0 提问者 回复 慕无忌2563680

谢谢你的回复,学习了
2018-12-20 回复 有任何疑惑可以回复我~
查看2条回复

sql运行机制和java运行机制不一样, sql语句只要配置合理,都是秒级的,甚至是毫秒级的,喜欢这个答案。只是看到有很多程序也存在使用第一种方法。不知道他们是怎么考虑的。既然mybatis可以那么方便的配置查询语句,貌似很多业务层都可以直接写到SQL语句里了,程序只是负责传参而已

0 回复 有任何疑惑可以回复我~

啊,你说的对,是我把sql语句看错了。

再分析一次,在不考虑缓存的情况下:

先执行username in ("select username from users where enable = 0") 这是1000次,返回500的基数

500 * 1000 = 500000,确实次数已经超过第一种很多了。

但是sql运行机制和java运行机制不一样,如果要比速度,肯定sql要快,根据我的开发经验,java很少写高量级的循环语句。sql语句只要配置合理,都是秒级的,甚至是毫秒级的。所以肯定是第二种最棒,要不我写了这么多年前端,也不会来研究数据了……


0 回复 有任何疑惑可以回复我~

我怎么觉得第二种不是1000+500 这么简单,select username from users where enable = 0数据库需要跑1000次,select amount from orders where status =“unpay”这里也是1000次,复合这一句and username in也是要*500次吧,难道我思路错了

0 回复 有任何疑惑可以回复我~

我觉得肯定是关键表查询效率要高:

假设username和amount都是1000条数据,第一种查询得到500条结果,第二种也是500条结果。

第一种方式:除去查询效率,二维for循环效率极低,需要对比500*500=250000次,总次数是1000 +1000 + 250000.

第二种:相当于先查询username的500条组成一个新的表,然后从结果500条中查询符合第二个条件的结果。总次数等于1000+500。

这效率一对比,就什么都不用说了。

0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消

关联表查询是单表查询出结果后再用程序过滤还是直接用SQL语句查询最终结果

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信