MySQL 实战宝典(七):MySQL 连接查询、嵌套子查询与性能优化原理

Hibernate底层原理:从延迟加载到二级缓存的深度解析 Hibernate作为Java生态主流ORM框架,其本质是一套对象-关系映射决策系统,而非简单SQL生成器。理解其核心机制需回归JPA规范与数据库交互的基本原理:延迟加载是对象图导航的性能契约,依赖Session生命周期与代理机制;一级缓存是事务内状态快照管理,失效由flush、merge、refresh等操作主动驱动;二级缓存则需根据架构形态(单体/微服务/分布式)权衡一致性、性能与运维成本。这些机制共同决定了持久层的可靠性、可观察性与扩展边界。本文聚焦Hibernate 5.6+在真实生产环境中的行为逻 阅读详情

摘要:在关系型数据库开发中,SQL 语句的编写质量直接决定了系统的性能上限。本文将深入剖析 MySQL 中最核心的两种查询方式——连接查询(JOIN)与嵌套子查询的底层执行原理,并揭秘 MySQL 优化器是如何基于 成本模型(Cost Model) 进行决策的。


一、连接查询:打破数据的孤岛

连接查询是关系型数据库的灵魂,它允许我们跨越表与表的边界检索数据。

1.1 全局概览 (MindMap)

首先,通过一张思维导图快速理清连接查询的分类与核心逻辑。

MySQL 连接查询

连接类型

INNER JOIN (内连接): 仅返回匹配行

LEFT JOIN (左外连接): 保留左表全部,右表补NULL

RIGHT JOIN (右外连接): 保留右表全部,左表补NULL

FULL JOIN (模拟): UNION LEFT & RIGHT

核心概念

驱动表 (Driver Table): 主动发起查询的表

被驱动表 (Driven Table): 被动匹配的表

过滤机制

ON 子句: 连接前的匹配条件 (保留外连接主表数据)

WHERE 子句: 连接后的筛选条件 (过滤最终结果)

1.2 四大连接模式详解

假设我们有两张表:employees (员工) 和 departments (部门)。

(1) INNER JOIN (内连接)

这是最严格的匹配,只有当“员工”找到了“部门”,且“部门”里有该“员工”时才展示。

SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.id;
(2) LEFT JOIN (左外连接)

以左表为尊。展示所有员工,哪怕他没有部门(部门字段显示 NULL)。

SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id;
(3) RIGHT JOIN (右外连接)

以右表为尊。展示所有部门,哪怕部门里没有员工。

SELECT e.name, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.id;
(4) FULL OUTER JOIN (全连接)

MySQL 原生不支持 FULL JOIN,但我们可以通过 UNION “拼”出来。注意 UNION 会自动去重。

-- 既要所有员工,也要所有部门
SELECT e.name, d.department_name FROM employees e LEFT JOIN departments d ON e.department_id = d.id
UNION
SELECT e.name, d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.id;

二、连接查询的底层原理与性能关键

理解原理是优化的前提。MySQL 使用嵌套循环连接 (Nested-Loop Join, NLJ) 算法来执行连接。

2.1 驱动表与被驱动表

  • 驱动表 (Driver Table):外层循环的表。MySQL 优化器会选择结果集更小的表作为驱动表。
  • 被驱动表 (Driven Table):内层循环的表。

2.2 执行流程时序图

下图展示了 LEFT JOIN 的执行过程(假设 Table A 是驱动表):

被驱动表(Table B) 驱动表(Table A) 执行器 被驱动表(Table B) 驱动表(Table A) 执行器 步骤1: 选取驱动表 步骤2: 带着R1去匹配 alt [索引命中] [无索引] loop [嵌套查找] 重复上述步骤直到 Table A 遍历完 读取第一行记录 (符合WHERE条件) 返回记录 R1 使用 R1.key 在 Table B 中查找 (ON条件) 快速返回匹配行 全表扫描 (性能杀手) 合并结果,生成最终行

2.3 ON 与 WHERE 的本质区别

这是开发者最容易混淆的地方,特别是在外连接中:

  • ON 子句:决定了被驱动表的记录是否被“匹配”。如果外连接中 ON 不匹配,驱动表的记录依然会被保留(被驱动表补 NULL)。
  • WHERE 子句:在连接操作完成后,对整个结果集进行“清洗”。如果不满足,整行记录(包括驱动表记录)都会被丢弃。

最佳实践:

  • 涉及两表连接关系的条件,必须写在 ON 中。
  • 只涉及单表数据的筛选,建议写在 WHERE 中(虽然优化器会自动优化,但这样语义更清晰)。

三、嵌套子查询 (Nested Subqueries) 性能陷阱

子查询虽然写法直观,但在 MySQL 早期版本(5.5及之前)性能极差,虽然 5.6+ 引入了 Materialization(物化)等优化,但仍需谨慎。

3.1 IN 子查询的陷阱

-- 找出有下属部门的经理
SELECT * FROM managers m 
WHERE m.dept_id IN (SELECT id FROM departments);

传统误区:我们以为 MySQL 会先执行子查询拿到 ID 列表,再查外层。
实际情况:在旧版本或特定场景下,MySQL 可能会把它改写为相关子查询,即 EXISTS 模式:

SELECT * FROM managers m 
WHERE EXISTS (SELECT 1 FROM departments d WHERE m.dept_id = d.id);

这意味着,外表 managers 有多少条记录,子查询就要执行多少次!如果外表很大,性能直接崩塌。

3.2 优化策略:子查询转 JOIN

绝大多数情况下,将子查询改写为 JOIN 是提升性能的捷径。

是 (依赖外层参数)

否 (独立运行)

子查询 SQL

是否相关子查询?

性能较差 (O(N*M))

视数据量而定

优化方案: 改写为 JOIN

优化代码示例:

-- 优化后:使用 JOIN 代替 IN
SELECT m.* 
FROM managers m
JOIN departments d ON m.dept_id = d.id;

此时,MySQL 优化器可以自由选择谁做驱动表,利用索引进行高效匹配。


四、MySQL 性能优化的核心:成本模型 (Cost Model)

为什么有时 MySQL 选错索引?为什么它不选我们认为更快的方案?因为 MySQL 是基于成本(Cost-Based) 的优化器。

4.1 成本的构成

MySQL 计算一条查询的成本公式大致如下:
T o t a l C o s t = C P U C o s t + I / O C o s t Total Cost = CPU Cost + I/O Cost TotalCost=CPUCost+I/OCost

  • I/O 成本:将数据页从磁盘加载到内存。默认成本常数 1.0。
  • CPU 成本:读取记录、检测条件、排序等。默认成本常数 0.2。

4.2 优化器决策流程

SQL 查询语句

语法解析

查询优化器

1. 找出所有可用索引
2. 计算全表扫描成本 (Table Scan)
3. 计算各索引扫描成本 (Index Scan)

对比成本

选择最低成本方案

生成执行计划

4.3 调节成本常数 (高级调优)

MySQL 将这些“定价标准”存在了系统表中,DBA 可以根据硬件情况进行修改。

(1) mysql.server_cost (Server 层成本)

主要控制 CPU 相关的逻辑操作成本。

成本名称默认值含义调优建议
disk_temptable_create_cost40.0创建磁盘临时表调大该值,迫使优化器尽量避免使用磁盘临时表
row_evaluate_cost0.2检测记录是否符合条件调大该值,会让优化器更倾向于使用索引
key_compare_cost0.1键值比较 (用于排序)调大该值,可减少 FileSort,倾向索引排序
(2) mysql.engine_cost (存储引擎层成本)

主要控制 I/O 操作成本。

  • io_block_read_cost (默认 1.0): 从磁盘读取一页的成本。
  • memory_block_read_cost (默认 1.0): 从内存读取一页的成本。

调优场景:
如果你使用的是高性能 NVMe SSD,磁盘 I/O 极快,可以适当调低 io_block_read_cost,告诉优化器:“读磁盘没那么贵,放心读”,这可能会让 MySQL 更愿意选择某些基于全表扫描但能避免回表的方案。


  • 总结与建议:
  1. 连接查询优先:在大部分场景下,JOIN 的性能优于复杂的嵌套子查询,尤其是当被驱动表上有索引时。
  2. 小表驱动大表:这是由 NLJ 算法决定的铁律。虽然优化器会自动选择,但复杂的 SQL 可能会迷惑优化器,开发者需心中有数。
  3. 索引是关键:连接条件(ON 字段)必须要有索引!否则就是 M × N M \times N M×N 的笛卡尔积式扫描,系统会瞬间卡死。
  4. 理解成本:MySQL 不会“猜”哪个快,它是“算”出来的。理解 I/O 和 CPU 成本,有助于我们理解 EXPLAIN 的结果,甚至通过调整 Cost Constants 进行深度调优。
【DataBase】使用联表查询比较慢如何进行优化? 如果查询的字段比较多,就需要对sql语句进行优化了,通过explain关键字加在慢sql前执行看是否走的索引,如果没有走索引就创建索引。 阅读详情

相关推荐

接口性能优化宝典:解决性能瓶颈的策略与实践

本文深入探讨了提升接口性能的多种策略,涵盖了数据库优化、远程调用、异步处理、事务优化、缓存机制、分库分表等方面的技术。通过直面常见性能瓶颈,本文详细讲解了如何优化 SQL 执行效率、避免重复调用、减少事务复杂性、提高并发度,并提供了实际应用的最佳实践和技术方案。此外,文章还结合具体的案例,阐述了如何通过合理选择和设计优化方案,解决常见的性能问题,帮助开发者构建高效、可扩展的系统架构。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 174万+

Mysql高级篇学习总结13:多表连接查询语句优化方法(带join语句)

多表连接查询语句优化方法(带join语句)

xueping_wu的博客 4975

某手sig3-ios算法 Chomper黑盒调用

本文主要是介绍Chomper的算法模拟执行,Chomper目前已经已经是能比较完整的模拟ios可执行文件执行的模拟器,在这块有非常大的优势。以前安卓端有强势的unidbg,现在iOS也有Chomper了,后续等待作者持续更新,完善Chomper。强势推荐一波-> Chomper地址: https://github.com/sledgeh4w/chomper。我这块也已经使用Chomper完成雅迪系列、某手的算法调用。后续也会有更多扩展。

成小新的博客 2156

MySQL中的Join连接查询

我们在进行表连接查询的时候一般都会使用JOIN xxx ON xxx的语法,ON语句的执行是在JOIN语句之前的,也就是说两张表数据行之间进行匹配的时候,会先判断数据行是否符合ON语句后面的条件,再决定是否JOIN,对参与 Join 操作的基表或视图进行过滤,之后再对两表进行 Join 操作,输出结果集。对于三表或多表 Join,则都是可以拆分为两表 Join 的方式进行处理,最先参与 Join 操作的两个表的 Join 的结果集,以表的形式参与后续的 Join 操作。我们来举个例子来简单理解笛卡尔积。

BlueProtocolBlog 2786

AI时代,程序员何去何从?别慌,看完这篇你就明白了

AI时代程序员的发展方向 摘要:随着AI代码助手的普及,程序员行业面临变革。本文通过实际案例展示AI写代码的能力与局限:AI能生成基础功能代码(如RESTful API、数据处理脚本),但缺乏业务理解、系统设计和复杂逻辑处理能力。程序员的核心价值在于需求分析、架构设计、性能优化等高层能力。未来程序员应: 掌握AI工具提升效率 专注于创新和架构设计 培养业务理解能力 持续学习新技术 AI不会取代程序员,但会淘汰不会使用AI的程序员。建议开发者拥抱AI工具,将其作为助手而非威胁,聚焦高价值工作。

yunque_xianguang的博客 907

EDEM在农业机械设计中的实战应用:以谷物收割机优化为例

本文以谷物收割机优化为例,详细阐述了EDEM离散元仿真软件在农业机械设计中的实战应用。通过构建精准的“数字谷物”模型与农机部件动态界面,利用GPU加速完成大规模颗粒系统仿真,有效诊断并解决了籽粒夹带损失与清选负荷不均等田间难题,实现了从仿真分析到田间验证的设计优化闭环。

weixin_29256771的博客 107

mysql的JOIN用法详解-附带查询示例

在 SQL 中,JOIN是用于将多个表中的数据连接在一起的操作。它通过指定连接条件将两个或多个表中符合条件的行组合起来,产生一个新的结果集。SQL 中常见的 JOIN 类型包括和。

厚积薄发. 9485

【小程序】支付宝直付通解决方案

支付宝直付通是支付宝为小程序提供的一种支付解决方案,可以实现小程序中直接使用支付宝进行支付。以上是一个简单的支付宝直付通解决方案及相关代码示例。具体的使用还需要根据自己的业务需求进行定制化开发和调整。

qq_31532979的贺公子之数据科学与艺术博客,致力于科技向善,拥抱开源,要用技术的影响力来领导团队,而不是威权和职位! 1281

【MySQL】连接查询(JOIN 关键字)—— 图文详解:内连接(INNER JOIN)、外连接(OUTER JOIN)、左连接(LEFT JOIN)、左外连接、右连接、右外连接、全连接、全外连接

【MySQL】连接查询(JOIN 关键字)—— 图解:内连接(INNER JOIN)、等值连接、自然连接(NATURAL JOIN)、交叉连接、外连接(OUTER JOIN)、左连接(LEFT JOIN)、左外连接(LEFT OUTER JOIN)、右连接(RIGHT JOIN)、右外连接(RIGHT OUTER JOIN)、全连接、全外连接。

我梦 7751

华为防火墙USG6600全流量日志配置指南:从流量监控到NAT日志的完整方案

本文详细介绍了华为USG6600防火墙全流量日志配置方案,涵盖流量监控、NAT日志及安全事件溯源等核心功能。通过精细化配置和性能优化技巧,帮助企业构建高效、合规的日志体系,提升网络安全运维效率。文章特别强调了日志采样与字段过滤的实用方法,适用于高流量环境下的资源优化。

gin88的博客 347

3D Slicer学习记录(4)-PLUSapp连接双目相机Intel Realsense

plusapp是基于openIGTLink协议的免费的开源库和应用程序API接口,用于数据采集、预处理、校准和实时流成像、位置跟踪和其他传感器数据。这里以intel realsense双目相机为例详细的演示整个图像流导入到3D Slicer的流程。

weixin_39090239的博客 1344

为什么 MySQL 不推荐使用 join?

点击下方“IT牧场”,选择“设为星标”1.对于mysql,不推荐使用子查询和join是因为本身join的效率就是硬伤,一旦数据量很大效率就很难保证,强烈推荐分别根据索引单表取数据,然后在程...

ITMuch的专栏 958

OpenClaw实战系列10(完结篇):企业级应用实战案例——从0到1搭建智能客服系统

本文以一家跨境电商公司为例,从需求分析、系统设计、分步搭建到上线运营,完整呈现智能客服系统的落地全过程。所有配置命令和截图均来自实测环境,你可以直接复制使用。

PeterPan的博客 1305

一文带你了解MySQL之基于成本的优化

MySQL执行一个查询可以有不同的执行方案,它会选择其中成本最低,或者说代价最低的那种方案去真正的执行查询。I/O成本我们的表经常使用的MyISAM、InnoDB存储引擎都是将数据和索引都存储到磁盘上的,当我们想查询表中的记录时,需要先把数据或者索引加载到内存中然后再操作。这个从磁盘到内存这个加载的过程损耗的时间称之为I/O成本。CPU成本读取以及检测记录是否满足对应的搜索条件、对结果集进行排序等这些操作损耗的时间称之为CPU成本。

Multis 1765

行人检测模型在海思平台上的部署:从 PyTorch 到 NNIE 深度优化与实践

摘要 本文详细介绍行人检测模型从PyTorch到海思NNIE平台的部署流程。首先分析了行人检测面临的挑战(尺度变化、遮挡、姿态多样性等)及边缘部署的优势(实时性、隐私保护等)。重点阐述了模型转换过程:PyTorch→ONNX→Caffe→NNIE-WK,其中PyTorch转ONNX需注意评估模式设置、虚拟输入匹配、操作集版本选择等关键点。文章旨在帮助开发者在海思3516D芯片上实现高效的行人检测,克服部署过程中的常见问题,最终实现边缘设备的实时目标检测能力。

FJN110的博客 216

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

MySQL -- 连接查询

MySQL使用连接查询(JOIN)是为了从多个相关表中获取数据。

Afison的博客 3930

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Mysql两表 join 查询方式

Mysql 两表join 查询

大猩猩的博客 8126

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

MySQL高级篇——关联查询和子查询优化

左外连接:优先右表创建索引,连接字段类型要一致、内连接:驱动表由数据量和索引决定、 join语句原理、子查询优化:拆开查询或优化成连接查询

种一棵树最好的时间是十年前,其次是现在 4181

MySql中的连接查询

外连接: 在外连接当中,两张表连接产生了主次关系 , 主要查询的是主表的数据 , 捎带着关联查询次表 , 即如果对方没有记录和我主表匹配 , 那么默认对方是null , outer关键字可以省略。内连接:A表和B表连接,A和B两张表没有主次关系是平等的 , 查询时只是将能够匹配上连接条件的数据查询出来 , 即如果没有匹配的就查询不出来 , inner关键字可以省略。当两张表进行连接查询,没有指定连接条件的时候,最终查询结果条数是两张表条数的乘积,这种现象被称为:笛卡尔积现象(笛卡尔发现的,这是。

欢迎阅读我的博客 2747

温故MySQL - 17 查询优化:连接查询优化

文章目录1. 连接查询的本质2. 内连接和外连接3. 连接查询的原理3. 关联查询的优化3.1 外连接优化3.2 内连接优化 1. 连接查询的本质 数据准备: create table t1( m1 int, n1 char(1) ); create table t2( m2 int, n2 char(1) ); insert into t1 values(1,'a'),(2,'b'),(3,'c'); insert into t2 values(2,'b'),(3,'c'),(4,'d'); 如

你今天真好看呀 1568

优化多表联表查询的常见方法归纳

SQL联表查询优化思路

wzc200406的博客 2688

MySQL(八)—— 连接查询

8. 连接查询8.1 distinct8.2 什么是连接查询8.3 连接查询的分类8.4 笛卡尔积现象8.5 内连接8.5.1 等值连接8.5.2 非等值连接8.5.3 自连接8.6 外连接8.6.1 右外连接8.6.2 左外连接8.7 三张表、四张表怎么连接 8. 连接查询 8.1 distinct   distinct:把查询结果去除重复记录。注意:原表数据不会被修改,只是查询结果去重。   distinct只能出现在所有字段的最前方:select distinct job from emp;。   .

大彤小忆的博客 3310

【MySQL】索引优化与关联查询优化

如果对索引的过滤条件中限制了一定范围,那么使用B+数来查询后,索引中剩下字段也就没有意义来。在过滤条件(WHERE)中使用了索引的情况下,要按照索引建立时的顺序从左往右筛选,如果中间跳过了某个字段,比如跳过了。在内连接中小表驱动大表,优化器会对两个表进行计算,将数据量小的表作为驱动表,数据量大的表作为被驱动表。使用了越多的属性来建立索引,会加快SQL查询的效率,能加速每一个属性的查询。,可以设置0为INT类型字段的初始值,空字符串为字符串类型的初始值。具有索引,因此,这里的被驱动表仍然是。

lrzHHl的博客 1596

MySQL 多表关联查询优化实践和原理解析

MySQL 多表关联查询优化实践和原理解析

kerwin的博客 8708

MySQL查询执行(六):join查询

到底可不可以使用join如果直接使用join语句, MySQL优化器可能会选择表t1或t2作为驱动表, 这样会影响我们分析SQL语句的执行过程。所以, 为了便于分析执行过程中的性能问题, 我改用straight_join让MySQL使用固定的连接方式执行查询, 这样优化器只会按照我们指定的方式去join。在这个语句里, t1 是驱动表, t2是被驱动表。

热爱数据库的小胖 1254

MySQL关联查询如何优化

前面讲了原理,从原理出发,讲一下优化的建议被驱动表的连接字段建立索引,因为建立索引的查询方式是效率最高的。left join 或者 right join 这种外连接的情况,要保证小表(小结果集)作为驱动表,大表(大结果集)作为被驱动表,这样性能更好。在查询字段的话,要避免写出 select * ,而是根据业务需要,需要查询出来的 select 出来就行,因为这些字段也会加入到 join buffer 中,减少额外的内存消耗。能够直接多表关联的尽量直接关联,不用子查询,因为子查询的效率更加低。

清晨qc的博客 2892
上一篇: MySQL 实战宝典(五):MySQL 索引——从 B+ 树原理到实战优化
下一篇: Dubbo快速入门(一):分布式与微服务、Dubbo基本概念
TracyCoder123
博客等级 码龄8年 1万+粉丝 226原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TracyCoder123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值