为什么MySQL不推荐使用子查询和join

本文探讨了在大规模数据环境下,为何避免使用MySQL的子查询和JOIN操作,以及如何在应用层实现更高效的数据库查询策略。介绍了应用层关联的优势,包括提高缓存效率、减少锁竞争、易于数据库拆分等,并讨论了不推荐使用JOIN的原因及替代方法。

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

前言:

1.对于mysql,不推荐使用子查询和join是因为本身join的效率就是硬伤,一旦数据量很大效率就很难保证,强烈推荐分别根据索引单表取数据,然后在程序里面做join,merge数据。

2.子查询就更别用了,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,这里多了一个创建和销毁临时表的过程。

3.如果是JOIN的话,它是走嵌套查询的。小表驱动大表,且通过索引字段进行关联。如果表记录比较少的话,还是OK的。大的话业务逻辑中可以控制处理。

4.数据库是最底层的,瓶颈往往是数据库。建议数据库只是作为数据store的工具,而不要添加业务上去。

一、应用层关联的优势:

  • 让缓存的效率更高。许多应用程序可以方便地缓存单表查询对应的结果对象。如果关联中的某个表发生了变化,那么就无法使用查询缓存了,而拆分后,如果某个表很少改变,那么基于该表的查询就可以重复利用查询缓存结果了。
  • 将查询分解后,执行单个查询可以减少锁的竞争
  • 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展
  • 查询本身效率也可能会有所提升。查询id集的时候,使用IN()代替关联查询,可以让MySQL按照ID顺序进行查询,这可能比随机的关联要更高效。
  • 可以减少冗余记录的查询。在应用层做关联查询,意味着对于某条记录应用只需要查询一次,而在数据库中做关联查询,则可能需要重复地访问一部分数据。从这点看,这样的重构还可能会减少网络和内存的消艳。
  • 更进一步,这样做相当于在应用中实现了哈希关联,而不是使用MySQL的嵌套循环关联。某些场景哈希关联的效率要高很多。

二、应用层关联的使用场景:

  • 当应用能够方便地缓存单个查询的结果的时候
  • 当可以将数据分布到不同的MySQL服务器上的时候
  • 当能够使用IN()的方式代替关联查询的时候
  • 并发场景多,DB查询频繁,需要分库分表

三、不推荐使用join的原因: 

1.DB承担的业务压力大,能减少负担就减少。当表处于百万级别后,join导致性能下降; 

2.分布式的分库分表。这种时候是不建议跨库join的。目前mysql的分布式中间件,跨库join表现不良。 

3.修改表的schema,单表查询的修改比较容易,join写的sql语句要修改,不容易发现,成本比较大,当系统比较大时,不好维护。

四、不使用join的解决方法: 

在业务层,单表查询出数据后,作为条件给下一个单表查询。也就是子查询。 会担心子查询出来的结果集太多。mysql对in的数量没有限制,但是mysql限制整条sql语句的大小。通过调整参数max_allowed_packet ,可以修改一条sql的最大值。建议在业务上做好处理,限制一次查询出来的结果集是能接受的。

五、再来说说join查询的好处:

1.做分页查询:

关联查询的好处时候可以做分页,可以用副表的字段做查询条件,在查询的时候,将副表匹配到的字段作为结果集,用主表去in它,但是问题来了,如果匹配到的数据量太大就不行了,也会导致返回的分页记录跟实际的不一样,解决的方法可以交给前端,一次性查询,让前端分批显示就可以了,这种解决方案的前提是数据量不太,因为sql本身长度有限。

喜欢的小伙伴请关注博主的公众号【细说架构】

### 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; ``` 两种写法都能达到目的,但在实际应用中应依据具体情况选择最合适的方案以优化性能。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值