MySQL子查询和join

本文探讨了在MySQL中,子查询效率低下的问题。当一个4w条记录的表a通过id与6k条记录的表b进行查询时,使用子查询效率较低。原因是MySQL实际执行时先获取外部表的id,再与内部表对比。通过实验对比,发现使用JOIN查询比子查询更快。总结建议在优化时考虑使用JOIN,并指出在某些情况下,先将大表数据取出,通过程序处理后再查询小表可能更为高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天做了一个很简单的子查询,表a有4w多条的数据,而b 有6k多条,代码如下:

SELECT * FROM a WHERE id IN (SELECT id FROM b)

但是效率却很慢,查询了书和网上的信息得到了如下的结论:

可以使用关联查询代替子查询。

比较了一下:

1:使用子查询的explain结果(两个表都有id的索引)

SELECT * FROM a WHERE id IN (SELECT id FROM b)




为什么会出现这种情况呢?

大家会认为mysql是先执行里面的sql,得到id(1,2,3,4),然后在执行外层的sql,select * from a where id in (1,2,3,4)

实际上,mysql是如下查询的

select * from a where exists (select * from b where b=6 and b.id = a.id)

mysql 先执行外面的表获取id,再到里面进行对比。

所以如果外面的表数据量越大,速度越慢。

因此可以使用join来代替。



2:使用关联查询

SELECT a.* FROM a join b on a.id=b.id


对比以上结果可以看出关联查询快的很多。


总结:

1:子查询的优化尽可能使用关联查询代替。

2:不能保证任何情况关联查询逗比子查询快,具体情况要看一下,那个更快一些。

3:其实不建议直接用mysql做关联查询,可以a表查出来后,通过程序拼接,再到b表里面去查。


### MySQL子查询JOIN 的区别及用法 #### 子查询的概念及其应用场景 子查询是在另一个 SQL 查询内部执行的查询语句。它可以嵌套在一个 SELECT、INSERT、UPDATE 或 DELETE 语句内,也可以作为其他子查询的一部分。子查询返回的结果可以是一个单值、一列或多行多列的数据。 当需要基于某个条件获取数据而这个条件依赖于另一张表中的某些记录时,通常会考虑使用子查询。例如,在查找不属于任何部门管理者的员工信息时,可以通过子查询来实现: ```sql SELECT * FROM employees WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager); ``` 此方法通过 `NOT IN` 来过滤掉那些存在于 `dept_manager` 表里的员工编号[^3]。 #### JOIN 概念及其应用场景 JOIN 是用来组合来自两个或多个表格的相关字段的一种方式。它允许我们根据一定的匹配规则将不同表之间的数据联系起来查看。常见的 JOIN 类型有 INNER JOIN(交集)、LEFT OUTER JOIN(左外连接)、RIGHT OUTER JOIN(右外连接)以及 FULL OUTER JOIN(全外连接)。其中 LEFT JOIN 可用于上述相同的需求表达如下: ```sql SELECT e.* FROM employees AS e LEFT JOIN dept_manager AS d ON e.emp_no = d.emp_no WHERE d.emp_no IS NULL; ``` 这段代码同样实现了筛选出不在管理层名单上的所有雇员的功能。 #### 性能对比分析 关于两者之间谁更优并没有绝对的答案,因为这取决于具体的应用环境数据库结构等因素。然而,一般而言,如果能够利用好索引,则 JOIN 往往会在处理大规模数据集合方面表现得更好一些;而对于相对较小规模的数据操作或是只需要简单判断是否存在的情况来说,适当运用子查询或许更加直观简便[^2]。 另外值得注意的是,在特定情况下采用 `IN()` 函数并传递一组预先计算好的 ID 列表给 MySQL 进行检索,相较于直接做复杂的联结运算可能会带来更高的效率提升,这是因为前者可以使服务器按既定次序访问磁盘文件从而减少不必要的 I/O 开销[^1]。 #### 实际案例展示 为了进一步说明这两种技术手段的不同之处,请看下面的例子:假设有一个名为 orders order_items 的两张表,现在想要找出订单总金额超过 $100 的客户姓名列表。 ##### 方法一:使用子查询 ```sql SELECT c.name FROM customers AS c WHERE EXISTS ( SELECT 1 FROM orders o JOIN order_items oi ON o.id = oi.order_id GROUP BY o.customer_id HAVING SUM(oi.price * oi.quantity) > 100 AND o.customer_id = c.id ); ``` ##### 方法二:使用 JOIN ```sql SELECT DISTINCT c.name FROM customers AS c JOIN orders AS o ON c.id = o.customer_id JOIN order_items AS oi ON o.id = oi.order_id GROUP BY c.id, c.name HAVING SUM(oi.price * oi.quantity) > 100; ``` 两种写法都能达到目的,但在实际应用中应依据具体情况选择最合适的方案以优化性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值