当前位置: 首页 > news >正文

从子查询到连接:提升数据库查询性能的 7 种方法

一般来说,连接(Join) 的性能通常优于子查询(Subquery),尤其是在涉及多表的复杂查询中。连接允许数据库优化器通过同时处理多个表的数据来创建更高效的执行计划。然而,性能差异可能因以下因素而有所不同:

  • • 查询复杂度

  • • 数据量及其分布

  • • 索引

  • • 数据库引擎优化

为了获得最佳性能,建议遵循以下最佳实践:

  1. 1. 检查查询执行计划,了解数据库如何处理查询。

  2. 2. 使用具有代表性的数据量测试连接和子查询版本的查询。

  3. 3. 使用适当的索引来支持查询。

  4. 4. 在考虑性能的同时,兼顾查询的可读性和可维护性。

以下是几种可以将子查询重写为连接的情况,并附上了表创建、数据集以及每个部分的查询链接。


1. 将 IN() 子查询替换为连接

使用 IN 的查询:

SELECT * 
FROM SalesOrderItems 
WHERE ProductID IN (
    SELECT ID 
    FROM Products 
    WHERE Quantity < 20
);

使用连接的查询:

SELECT s.* 
FROM SalesOrderItems s
JOIN Products p ON s.ProductID = p.ID
WHERE p.Quantity < 20;

None

区别:连接直接匹配 SalesOrderItems 和 Products 表中的行,避免了在子查询中创建 ID 列表的中间步骤。这对于大数据集尤其高效。


2. 替换关联子查询

使用关联子查询的查询:

SELECT employee_id, first_name 
FROM employees e
WHERE salary > (
    SELECT AVG(salary) 
    FROM employees e2 
    WHERE e2.department_id = e.department_id
);

使用连接和聚合的查询:

WITH AvgSalaries AS (
    SELECT department_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department_id
)
SELECT e.employee_id, e.first_name 
FROM employees e
JOIN AvgSalaries a ON e.department_id = a.department_id
WHERE e.salary > a.avg_salary;

None

区别:通过预先计算每个部门的平均工资,连接避免了为外部查询的每一行执行子查询。


3. 替换 EXISTS 子查询

使用 EXISTS 的查询:

SELECT employee_id, first_name 
FROM employees e
WHERE EXISTS (
    SELECT 1 
    FROM departments d 
    WHERE d.department_id = e.department_id AND d.location = 'New York'
);

使用连接的查询:

SELECT DISTINCT e.employee_id, e.first_name 
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.location = 'New York';

None

区别:连接消除了为 employees 表中的每一行评估子查询的需要,同时保持相同的结果。


4. 替换嵌套子查询

使用嵌套子查询的查询:

SELECT employee_id, first_name 
FROM employees 
WHERE salary > (
    SELECT AVG(salary) 
    FROM employees 
    WHERE department_id = (
        SELECT department_id 
        FROM departments 
        WHERE department_name = 'Sales'
    )
);

使用连接的查询:

WITH SalesDept AS (
    SELECT department_id 
    FROM departments 
    WHERE department_name = 'Sales'
),
AvgSalary AS (
    SELECT AVG(salary) AS avg_salary 
    FROM employees 
    WHERE department_id IN (SELECT department_id FROM SalesDept)
)
SELECT employee_id, first_name 
FROM employees 
WHERE salary > (SELECT avg_salary FROM AvgSalary);

None

区别:将嵌套子查询扁平化为 CTE 或连接,简化了执行计划并减少了冗余计算。


5. 替换 SELECT 子句中的子查询

使用子查询的查询:

SELECT c.CategoryName, 
       (SELECT MAX(UnitPrice) FROM Products p 
WHERE p.CategoryId = c.CategoryId) AS MaxPrice
FROM Categories c;

使用连接的查询:

WITH MaxPrices AS (
    SELECT CategoryId, MAX(UnitPrice) AS MaxPrice
    FROM Products
    GROUP BY CategoryId
)
SELECT c.CategoryName, m.MaxPrice
FROM Categories c
LEFT JOIN MaxPrices m ON c.CategoryId = m.CategoryId;

None

区别:预先计算每个类别的最高价格,避免了为 Categories 表中的每一行重复计算。


6. 替换 NOT IN 子查询

使用 NOT IN 的查询:

SELECT P.*
FROM Products P
WHERE P.CategoryId NOT IN (SELECT CategoryId FROM Categories);

使用左连接的查询:

SELECT t1.*
FROM Products t1
LEFT JOIN Categories t2 ON t1.CategoryId = t2.CategoryId
WHERE t2.CategoryId IS NULL;

区别:左连接直接识别不匹配的行,而无需评估整个子查询结果集,并且可以处理 NULL 值,而 NOT IN 则不能。


7. 替换标量子查询

使用标量子查询的查询:

SELECT o.order_id, o.total_amount,
       (SELECT CompanyName FROM Customers c 
WHERE c.customer_id = o.customer_id) AS CompanyName
FROM Orders o;

使用连接的查询:

SELECT o.order_id, o.total_amount, c.CompanyName
FROM Orders o
JOIN Customers c ON o.customer_id = c.customer_id;

None

区别:直接连接避免了为 Orders 表中的每一行执行子查询,这对于大数据集来说可能非常耗时。


总结

连接更好地利用索引,并通过一步处理数据来减少冗余计算,而不是重复评估子查询。

相关文章:

  • 生成式AI课程 比较好
  • C++:重载操作符
  • APM-基于Grafana生态以及OTLP协议的Java轻量级日志监控系统
  • Qt信号槽函数
  • springBoot中雪花算术法
  • 导出sql命令
  • 融合YOLO11与行为树的人机协作智能框架:动态工效学优化与自适应安全决策
  • LabVIEW医疗设备备用电源实时监控系统
  • Activiti工作流
  • CH32V208GBU6沁恒协议栈BUG:在主机Write的同一包notify会造成主机一直Write不成功;最终还是用心跳包来解决
  • 进程、线程和协程
  • Leecode Hot50
  • Zerotier虚拟局域网在树莓派的应用和Syncthing配合Zerotier实现端到端文件同步
  • Spring AOP面向切面编程实现日志功能
  • 第 五 章:优化算法_《C++性能优化指南》_notes
  • 在 CentOS 系统中开机自动执行 Shell 脚本
  • vue vue3 走马灯Carousel
  • 正则表达式-万能表达式
  • (二)手眼标定——概述+原理+常用方法汇总+代码实战(C++)
  • 第三章:测量性能_《C++性能优化指南》_notes
  • 普京发表声明感谢协助俄军收复库尔斯克州的朝鲜军人
  • 榆林市委常委王华胜已任榆林市政协党组书记
  • 识味顺德︱顺德菜的醉系列与火滋味
  • 对外投资增长、消费市场持续升温,中国经济砥砺前行
  • 精准滴灌“种企业”,苏南强县常熟新的进阶密码
  • 中国经济“第一省会”广州,从传统商贸中心到直播电商第一城