【第8天】每天一个MySQL知识点,百日打怪升级

本文涉及的产品
RDS AI 助手,专业版
PolarDB Agent Express,2核4GB
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 本文系统解析MySQL中SELECT语句的完整执行流程:从连接器验权、(已移除的)查询缓存、解析器语法检查、预处理器语义校验,到优化器索引选择与执行器调用存储引擎取数。涵盖面试高频考点与实战避坑指南,助DBA深入理解SQL底层机制。(239字)

SQL基础:SELECT执行流程


大家好,我是一名拥有10年以上经验的DBA老兵。

做这个系列,源于一个朴素的愿望:把踩过的坑、总结的经验系统化输出,希望能帮到刚入行或想进阶的兄弟们。

让我们开始今天的第8天内容。


🎯 面试考点

  • SELECT 语句从输入到输出经历了哪些步骤?
  • 查询缓存为什么在 MySQL 8.0 被移除了?
  • 优化器是怎么选择索引的?
  • 执行器是怎么获取数据的?

背景引入

💡 说白了:你以为 SELECT 只是查一下?其实它跑了半个数据库

你有没有想过:

  • 你敲下 SELECT * FROM user WHERE id = 1,MySQL 到底做了什么?
  • 为什么有时候明明加了索引,MySQL 却不用?
  • 为什么同样的 SQL,有时候快有时候慢?

说实话,不理解 SELECT 执行流程的 DBA,就像不知道汽车怎么跑的司机——能开,但出了问题只能干瞪眼。

今天的目标:搞懂 SELECT 语句的完整执行流程,面试必问


核心概念

执行流程全景图

image.png


第一步:连接器

💡 说白了:连接器就是门卫,验明正身才让进

职责

  • 建立 TCP 连接
  • 验证用户名密码
  • 获取用户权限(后续操作都依赖这个权限)

面试必问

  • 为什么有时候连接很慢?
  • 长连接和短连接有什么区别?
  • 为什么长连接会导致内存泄漏?

面试解答

Q: 为什么有时候连接很慢?

因为建立 TCP 连接需要三次握手,如果数据库服务器距离远或者网络差,连接就会慢。建议使用连接池,复用连接。

Q: 长连接和短连接有什么区别?

短连接:每次执行完 SQL 就断开连接。长连接:执行完 SQL 后保持连接,下次复用。长连接减少了建立连接的开销,但会导致内存增长。


第二步:查询缓存(MySQL 8.0 已移除)

💡 说白了:查询缓存就是"抄作业",SQL 完全一样就直接返回结果

工作机制

  1. 检查 SQL 是否命中缓存(精确匹配,包括空格)
  2. 命中 → 直接返回结果
  3. 未命中 → 继续执行后续步骤,结果放入缓存

为什么 MySQL 8.0 移除了?

  • 缓存失效太频繁:表有任何更新,该表所有缓存失效
  • 命中率低:业务 SQL 通常有参数差异
  • 维护成本高:需要额外的锁机制
-- MySQL 5.7 可以手动关闭查询缓存
SET GLOBAL query_cache_type = 0;

-- 查看缓存状态
SHOW STATUS LIKE 'Qcache%';

第三步:解析器

💡 说白了:解析器就是"语文老师",检查 SQL 语法对不对

职责

  • 词法分析:识别关键字、表名、列名
  • 语法分析:检查 SQL 语法是否正确
-- 语法错误示例
SELEC * FROM user;  -- 报错:SELEC 不是有效关键字

-- 语义错误示例(解析器检查不出,在预处理器报错)
SELECT * FROM user WHERE non_exist_column = 1;  -- 如果列不存在,在预处理器报错

第四步:预处理器

💡 说白了:预处理器就是"班主任",检查表和列是否存在

职责

  • 检查表名、列名是否存在
  • 检查用户是否有权限访问这些表和列
  • 展开 SELECT * 为具体列名
-- 预处理器会检查
SELECT * FROM user WHERE age > 18;

-- 等价于
SELECT id, name, age, ... FROM user WHERE age > 18;

第五步:优化器

💡 说白了:优化器就是"军师",决定怎么执行最高效

职责

  • 选择使用哪个索引
  • 决定表的连接顺序
  • 选择最优的执行计划

优化器的工作原理

-- 优化器会考虑以下因素
EXPLAIN SELECT * FROM user WHERE age > 18 AND city = '北京';

-- 优化器可能选择:
-- 方案1:使用 idx_age 索引,然后回表过滤 city
-- 方案2:使用 idx_city 索引,然后回表过滤 age
-- 方案3:使用联合索引 idx_age_city(如果存在)

面试必问

  • 优化器是基于什么选择索引的?
  • 优化器选择错了怎么办?

面试解答

Q: 优化器是基于什么选择索引的?

基于统计信息(cardinality、数据分布等)估算成本,选择成本最低的执行计划。但统计信息可能不准确,导致优化器选错索引。

Q: 优化器选择错了怎么办?

可以使用 FORCE INDEX 强制指定索引,或者 ANALYZE TABLE 更新统计信息。


第六步:执行器

💡 说白了:执行器就是"干活的人",真正去存储引擎取数据

职责

  • 根据执行计划,调用存储引擎的接口获取数据
  • 对结果进行过滤、排序、聚合等处理
-- 执行器的工作流程
SELECT * FROM user WHERE age > 18;

-- 1. 调用存储引擎的索引接口,获取满足条件的记录ID
-- 2. 调用存储引擎的行读取接口,获取完整行数据
-- 3. 返回结果集给客户端

实战案例

场景一:查看 SELECT 执行流程

-- 开启性能监控
SET profiling = 1;

-- 执行查询
SELECT * FROM user WHERE id = 1;

-- 查看执行过程
SHOW PROFILES;
SHOW PROFILE FOR QUERY 1;

输出示例

+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000045 |
| checking permissions | 0.000006 |
| Opening tables       | 0.000015 |
| init                 | 0.000008 |
| System lock          | 0.000006 |
| optimizing           | 0.000004 |
| statistics           | 0.000012 |
| preparing            | 0.000008 |
| executing            | 0.000003 |
| Sending data         | 0.000035 |
| end                  | 0.000003 |
| query end            | 0.000002 |
| closing tables       | 0.000004 |
| freeing items        | 0.000015 |
| cleaning up          | 0.000003 |
+----------------------+----------+

场景二:优化器选错索引

-- 创建测试表
CREATE TABLE orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    status VARCHAR(20),
    amount DECIMAL(10,2),
    create_time DATETIME,
    INDEX idx_user_id (user_id),
    INDEX idx_status (status),
    INDEX idx_create_time (create_time)
);

-- 插入数据(status 分布不均匀)
INSERT INTO orders (user_id, status, amount, create_time)
SELECT 
    FLOOR(RAND() * 10000),
    CASE WHEN RAND() < 0.9 THEN 'completed' ELSE 'pending' END,
    ROUND(RAND() * 1000, 2),
    DATE_ADD('2026-01-01', INTERVAL FLOOR(RAND() * 365) DAY)
FROM (
    WITH RECURSIVE cte AS (SELECT 1 AS n UNION ALL SELECT n+1 FROM cte WHERE n<100000)
    SELECT * FROM cte
) tmp;

-- 查看执行计划
EXPLAIN SELECT * FROM orders WHERE status = 'pending' AND create_time > '2026-06-01';

-- 优化器可能选错索引,强制指定
SELECT * FROM orders FORCE INDEX(idx_create_time) WHERE status = 'pending' AND create_time > '2026-06-01';

💡 AI 辅助实战

🤖 AI 能不能帮我对比不同 SQL 写法的执行流程?

能!让 AI 分析同一需求的不同写法,对比执行流程和性能差异:

提示词示例:

"以下两种写法都能查询有订单的用户,请分析执行流程有什么区别:

写法1(子查询):
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders)

写法2(JOIN):
SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id

请分析:
1. 两种写法的执行流程
2. 哪种写法性能更好
3. 什么场景下选择哪种写法"

AI 分析结果

对比项 写法1(子查询) 写法2(JOIN)
执行流程 先执行子查询,再用 IN 匹配 先 JOIN,再去重
索引使用 可能无法使用索引 可以使用索引
临时表 可能需要临时表 需要临时表去重
性能 数据量大时较慢 通常更快

AI 优化建议

  • 写法1 改成 EXISTS 或 JOIN
  • 写法2 可以用 GROUP BY 代替 DISTINCT
  • 都可以加索引优化

避坑指南

⚠️ 真实踩过的坑:

  1. 不要迷信 EXPLAIN

    • EXPLAIN 只是优化器的预估,一般不会有太大偏差,但它不是实际执行情况
    • 建议:用 EXPLAIN ANALYZE(MySQL 8.0+)看真实执行
  2. 长连接要定期重置

    • 长连接会导致内存增长(临时表、排序缓冲区等)
    • 建议:定期调用 mysql_reset_connection() 重置会话状态

    C API 示例

    MYSQL *conn = mysql_init(NULL);
    mysql_real_connect(conn, "localhost", "root", "", "test", 0, NULL, 0);
    
    mysql_query(conn, "SELECT * FROM user");
    
    // 重置连接(不断开,只清理会话状态)
    mysql_reset_connection(conn);
    
  3. 优化器统计信息要定期更新

    • 统计信息过期会导致优化器选错索引
    • 建议:定期执行 ANALYZE TABLE

思考题

🤔 互动时间:

  1. 如果 SELECT 语句执行很慢,你会按什么顺序排查?
  2. 为什么 MySQL 8.0 移除了查询缓存?
  3. 优化器选错了索引,除了 FORCE INDEX,还有什么办法?

总结

🎯 面试考点

  • 执行流程:连接器 → 查询缓存 → 解析器 → 预处理器 → 优化器 → 执行器
  • 连接器:权限验证、长连接/短连接
  • 查询缓存:MySQL 8.0 已移除,因为失效频繁、命中率低
  • 解析器:词法分析、语法分析
  • 优化器:基于统计信息选择最优执行计划
  • 执行器:调用存储引擎获取数据

下期预告:WHERE子句优化技巧 —— 面试必问!

全本合集《每天一个MySQL知识点,百日打怪升级》

您的关注是我每日更新的动力:没有那多


有问题欢迎评论区交流,明天见!

相关文章
|
2月前
|
SQL 缓存 Java
【MyBatis】MyBatis框架知识(全体系总结)
MyBatis 是一款轻量级持久层框架,支持SQL与代码分离、动态SQL、灵活映射及一二级缓存。本文系统讲解其核心组件、配置文件、Mapper映射、CRUD、缓存机制、插件扩展(如PageHelper、MyBatis-Plus)及最佳实践,助你高效掌握ORM开发。
1046 3
|
3月前
|
人工智能 API 机器人
OpenClaw 用户部署和使用指南汇总
本文档为OpenClaw(原MoltBot)官方使用指南,涵盖一键部署(阿里云轻量服务器年仅68元)、钉钉/飞书/企微等多平台AI员工搭建、典型场景实践及高频问题FAQ。同步更新产品化修复进展,助力用户高效落地7×24小时主动执行AI助手。
29460 253
|
人工智能 运维 关系型数据库
智能运维+多模型服务能力,阿里云 RDS AI 助手旗舰版正式上线!
RDS AI 助手旗舰版在 RDS AI 助手专业版智能运维能力的基础上,提供灵活模型选择、智能模型路由、多模型灾备、API Key 集成等更自主可控、灵活便捷的模型服务,并支持纳管运维各类环境部署的数据库。
智能运维+多模型服务能力,阿里云 RDS AI 助手旗舰版正式上线!
|
24天前
|
SQL 关系型数据库 MySQL
EXPLAIN 执行计划:一眼看穿你的SQL慢在哪
数据库小学妹带你轻松掌握SQL性能诊断!通过EXPLAIN查看执行计划,精准识别索引失效、全表扫描(ALL)、key为NULL等瓶颈。聚焦type、key、rows等6个关键字段,结合实战案例与避坑指南(如函数滥用、最左前缀破坏),让优化有的放矢。学完即用,告别盲目调优!
|
2月前
|
SQL XML Java
MyBatis学习知识点大全(一)
教程来源 https://app-abggx9rbr6dd.appmiaoda.com MyBatis 是轻量级Java持久层框架,简化JDBC开发,支持XML/注解映射、动态SQL、缓存及Spring集成。本文系统梳理其核心概念、架构原理、环境搭建与动态SQL等关键知识点,助力初学者构建完整知识体系,也为开发者提供深度技术参考。
|
7月前
|
传感器 人工智能 监控
拔俗多模态跨尺度大数据AI分析平台:让复杂数据“开口说话”的智能引擎
在数字化时代,多模态跨尺度大数据AI分析平台应运而生,打破数据孤岛,融合图像、文本、视频等多源信息,贯通微观与宏观尺度,实现智能诊断、预测与决策,广泛应用于医疗、制造、金融等领域,推动AI从“看懂”到“会思考”的跃迁。
627 0
|
SQL 缓存 Java
【吐血整理】MyBatis从入门到精通
本文介绍了 MyBatis 的使用指南,涵盖开发环境搭建、基础操作实例和进阶特性。首先,详细描述了 JDK 和 IDE 的安装及依赖引入,确保项目顺利运行。接着,通过创建用户表和实体类,演示了 CRUD 操作的全流程,包括查询、插入、更新和删除。最后,深入探讨了动态 SQL 和缓存机制等高级功能,帮助开发者提升数据库交互效率和代码灵活性。掌握这些内容,能显著提高 Java 编程中的数据库操作能力。
2006 4
|
5月前
|
缓存
浏览器缓存
HTTP缓存依赖Cache-Control与ETag。Cache-Control通过public、private、no-cache等指令控制缓存范围与行为,max-age、s-maxage定义过期时间,must-revalidate确保过期后校验。ETag为资源生成唯一标识,配合If-None-Match实现对比验证。结合Last-Modified与If-Modified-Since进行时间戳比对,或通过内容哈希生成ETag,实现精准缓存更新,提升性能。