10个案例告诉你mysql不使用子查询的原因

大家好,我是 V 哥,上周跟一个哥们吃饭,技术人在一起,你知道的,没聊上一会儿,就转到技术问题探讨上了,其中聊到数据库子查询的问题印象深刻,回来整理了以下10个案例说明不使用子查询的问题,分享给大家。

首先,来说一下在MySQL中,不推荐使用子查询和JOIN的原因,主要有以下几点:

  1. 性能问题 :子查询在执行时,MySQL需要创建临时表来存储内层查询的结果,查询完毕后再删除这些临时表,这会增加CPU和IO资源的消耗,产生慢查询。JOIN操作本身效率也是硬伤,特别是当数据量很大时,性能难以保证。

  2. 索引失效 :子查询可能导致索引失效,因为MySQL会将查询强行转换为联接来执行,这使得子查询不能首先被执行,如果外表很大,性能上会出问题。

  3. 查询优化器的复杂度 :子查询会影响查询优化器的判断,导致不够优化的执行计划。相比之下,联表查询更容易被优化器理解和处理。

  4. 数据传输开销 :子查询可能导致大量不必要的数据传输,因为每个子查询都需要将结果返回给主查询,而联表查询则可以通过一次查询返回所需的所有数据,减少数据传输的开销。

  5. 维护成本 :使用JOIN写的SQL语句在修改表的schema时比较复杂,成本较大,尤其是在系统较大时,不易维护。

针对这些原因,可以采取以下解决方案:

  1. 应用层关联 :在业务层单表查询出数据后,作为条件给下一个单表查询,减少数据库层的负担。

  2. 使用IN代替子查询 :如果子查询结果集比较小,可以考虑使用“IN”操作符进行查询,这在数据量较小的情况下,查询效率更高。

  3. 使用WHERE EXISTS :WHERE EXISTS是一种比“IN”更好的方案,它会检查子查询是否返回结果集,查询速度能够明显提高。

  4. 改写为JOIN :使用JOIN查询来替代子查询,不需要建立临时表,速度更快,如果查询中使用索引,性能会更好。

接下来,V 哥通过10个案例来直观的介绍一下。

案例1:查询所有有库存的商品信息。

  • 原始查询 (使用子查询):查询字段太多,就用*号替代了哈,不用在意,实际项目中肯定是不这样使用的。

    sql
    SELECT * FROM products WHERE id IN (SELECT product_id FROM inventory WHERE stock > 0);

这个查询会导致查询速度慢,影响用户体验。

  • 优化方案 (使用EXISTS):

    sql
    SELECT * FROM products WHERE EXISTS (SELECT 1 FROM inventory WHERE inventory.product_id = products.id AND inventory.stock > 0);

这个优化方案可以大幅提升查询速度,改善用户体验。

案例2:使用EXISTS优化子查询

原始查询

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
```

优化方案

```sql
SELECT * FROM orders WHERE EXISTS (SELECT 1 FROM customers WHERE orders.customer_id = customers.customer_id AND customers.country = 'USA');
```

使用EXISTS代替IN子查询可以减少回表查询的次数,提高查询效率。

案例3:使用JOIN代替子查询

原始查询

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
```

优化方案

```sql
SELECT o.* FROM orders o JOIN customers c ON o.customer_id = c.customer_id WHERE c.country = 'USA';
```

使用JOIN代替子查询可以减少子查询的开销,并且更容易利用索引。

案例4:优化子查询以减少数据量

原始查询

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers);
```

优化方案

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE active = 1);
```

限制子查询返回的数据量,减少主查询需要检查的行数,提高查询效率。

案例5:使用索引覆盖

原始查询

```sql
SELECT customer_id FROM customers WHERE country = 'USA';
```

优化方案

```sql
CREATE INDEX idx_country ON customers(country);
SELECT customer_id FROM customers WHERE country = 'USA';
```

country字段创建索引,使得子查询可以直接在索引中找到数据,避免回表查询。

案例6:使用临时表优化复杂查询

原始查询

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE last_order_date > '2023-01-01');
```

优化方案

```sql
CREATE TEMPORARY TABLE temp_customers AS SELECT customer_id FROM customers WHERE last_order_date > '2023-01-01';
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM temp_customers);
```

对于复杂的子查询,使用临时表存储中间结果,简化查询并提高性能。

案例7:使用窗口函数替代子查询

原始查询

```sql
SELECT employee_id, salary, (SELECT AVG(salary) FROM employees WHERE department_id = e.department_id) AS avg_salary FROM employees e;
```

优化方案

```sql
SELECT employee_id, salary, AVG(salary) OVER (PARTITION BY department_id) AS avg_salary FROM employees;
```

使用窗口函数替代子查询,提高查询效率。

案例8:优化子查询以避免全表扫描

原始查询

```sql
SELECT * FROM users WHERE username IN (SELECT username FROM orders WHERE order_date = '2024-01-01');
```

优化方案

```sql
CREATE INDEX idx_order_date ON orders(order_date);
SELECT * FROM users WHERE username IN (SELECT username FROM orders WHERE order_date = '2024-01-01');
```

order_date字段创建索引,避免全表扫描,提高子查询效率。

案例9:使用LIMIT子句限制子查询返回数据量

原始查询

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA');
```

优化方案

```sql
SELECT * FROM orders WHERE customer_id IN (SELECT customer_id FROM customers WHERE country = 'USA' LIMIT 100);
```

使用LIMIT子句限制子查询返回的数据量,减少主查询需要处理的数据量,提高查询效率。

案例10:使用JOIN代替子查询以利用索引

原始查询

```sql
SELECT * FROM transactions WHERE product_id IN (SELECT product_id FROM products WHERE category = 'Equity');
```

优化方案

```sql
SELECT t.* FROM transactions t JOIN products p ON t.product_id = p.product_id WHERE p.category = 'Equity';
```

使用JOIN代替子查询,并且可以更容易地利用products表上的category索引。

这些案例展示了如何通过不同的优化策略来提升MySQL查询性能,特别是在处理子查询时。

最后

通过上述分析和案例,我们可以看到,在实际业务场景中,替代子查询和JOIN的高效编程方法能够在不同场景下显著提升MySQL数据库的查询性能。在实际应用中,应根据具体业务需求和数据特点,灵活选择合适的优化方案。关注威哥爱编程,痴迷技术咱是认真滴。官人,都看到这了,高低点个赞再走呗,V 哥感谢你的支持。

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/4878.html

(0)
LomuLomu
上一篇 2024 年 12 月 30 日 上午7:50
下一篇 2024 年 12 月 30 日 上午8:51

相关推荐

  • 【Java 温故而知新系列】基础知识-02 数据基本类型

    1、Java基本数据类型 Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。 基本数据类型 数值型:整数类型(byte,short,int,long) ;浮点类型(float,double) 字符型:char 布尔型:boolean 类型 类型名称 关键字 占用内存 取值范围 默认值 整型 字节型 byt…

    2024 年 12 月 28 日
    55000
  • Java刷题常见的集合类,各种函数的使用以及常见的类型转化等等

    目录 前言 集合类 ArrayList 1. 创建和初始化 ArrayList 2.添加元素 add 3.获取元素 get 4.删除元素 remove 5.检查元素 6.遍历 ArrayList LinkedList Stack 1. 创建Stack对象 2. 压入元素 (push) 3. 弹出元素 (pop) 4. 查看栈顶元素 (peek) 5. 检查栈…

    2025 年 1 月 6 日
    56300
  • SuperGrok开通会员充值完整步骤

    国内用户开通 Grok Super 的充值教程,整理 Grok 充值、代充、国内支付、账号 ID 获取和确认充值步骤。

    未分类 2026 年 6 月 5 日
    2900
  • 双非二本,毕业一年多培训无果,拿到大厂 Offer

    大家好,我是R哥。 今天给大家分享一个逆袭的真实故事,本文的主人公小明(化名),小明是一名 2023 届往届生 ,毕业后因为种种原因,整整空档了一年多 。 小明的情况让我看了不禁感叹:“唉,这兄弟怎么搞啊的?这么年轻就躺平了? ”,毕竟,大家都知道,互联网行业的就业压力一年比一年大,稍微掉队,就可能被甩在后头,更别说还没就业就有这么长的空窗期。 然后,他选择…

    2025 年 1 月 16 日
    65200
  • 【GreatSQL优化器-10】find_best_ref

    【GreatSQL优化器-10】find_best_ref 一、find_best_ref介绍 GreatSQL的优化器对于join的表需要根据行数和cost来确定最后哪张表先执行哪张表后执行,这里面就涉及到预估满足条件的表数据,在keyuse_array数组有值的情况下,会用find_best_ref函数来通过索引进行cost和rows的估计,并且会找出最…

    2025 年 1 月 13 日
    56800

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信