一、先通关!连接器:MySQL 的 “前台小姐姐”
你以为敲下 SQL 的瞬间就开始执行了?太天真!第一步,你的请求得先 “刷脸进门”,这就是连接器(Connector) 的活儿。
想象你走进一家叫 “MySQL” 的餐厅,门口站着个前台小姐姐(连接器),她干的三件事和数据库里一模一样:
- 核实身份:你得报上用户名(root)和密码,她对照 “员工名册”(mysql.user 表)检查你是不是真顾客。密码错了?直接甩你一句 “Access denied”,跟餐厅 “非会员禁止入内” 一个意思。
- 分配权限:确认身份后,她会记下你的 “消费等级”—— 你能看哪些表(SELECT 权限)、能改哪些数据(UPDATE 权限),后续不管你点啥菜(执行啥 SQL),都得按这个权限来。
- 占座待命:验证通过后,她会给你分配一个 “餐桌”(TCP 连接),只要你不主动断开(
quit),或者超过wait_timeout(默认 8 小时)没动静被 “清桌”,这个连接就一直有效。
小插曲:如果你开了连接不干活,就会出现 “睡眠连接”(Sleep 状态),像占着茅坑不拉屎,多了会拖慢餐厅效率(数据库性能),所以记得及时释放连接!
二、(已退休!)查询缓存:记性差的 “传菜员”
在 MySQL 8.0 版本前,进门后还有个叫查询缓存(Query Cache) 的传菜员,现在已经被开除了 —— 为啥?因为这哥们儿 “记性差还爱添乱”。
他的工作逻辑很简单:把你之前点过的 “一模一样的菜”(完全相同的 SQL 语句)和对应的 “菜”(查询结果)存在柜子里。下次你再点,他直接从柜子里拿,不用后厨重做,听起来挺高效?
但问题来了:
- 认死理:SQL 语句差一个空格都不行,
SELECT * FROM t和SELECT * FROM t(多了个空格),在他眼里就是两道完全不同的菜,白存了。 - 易失效:只要这张表(t)被修改过(比如 INSERT/UPDATE),他柜子里所有和 t 相关的缓存都会被清空。对于经常更新的表,缓存刚存完就失效,纯属瞎忙活。
所以 MySQL 团队想了想:“留着你净添堵,不如开除!” 8.0 版本后,查询缓存正式退休,咱们直接跳过这一步,往后厨走。
三、语法检查!解析器:挑刺的 “点菜员”
过了前台,终于到了点菜环节,接待你的是解析器(Parser) —— 一个 “语法强迫症” 晚期的点菜员。
他拿到你写的 “菜单”(SQL 语句),会干两件事,确保你没瞎写:
- 词法分析:先把 SQL 拆成 “单词”,比如把
SELECT name FROM user WHERE id=1拆成 “SELECT”“name”“FROM”“user”“WHERE”“id”“1”,确认每个 “单词” 都是 MySQL 认识的(比如不会把 SELECT 写成 SELEC)。 - 语法分析:再检查 “句子结构” 对不对,比如有没有 FROM、WHERE 是不是写在正确的位置、括号有没有配对。如果你的 SQL 是
SELECT name FROM WHERE id=1(少了表名),他会直接把菜单扔回来,甩你一句错误:You have an error in your SQL syntax—— 像极了点菜员对你说:“你点的‘宫保鸡丁不要鸡丁’是什么玩意儿?语法不对!”
解析器的最终目标,是把 SQL 转换成一个 “抽象语法树(AST)”,相当于把你写的 “歪歪扭扭的菜单” 整理成 “后厨能看懂的标准化订单”,方便后续步骤处理。
四、最优解!优化器:精打细算的 “厨师长”
拿到标准化订单后,不是直接扔给厨师做菜,而是先送到优化器(Optimizer) —— 餐厅里的 “厨师长”,负责制定 “最高效的做菜方案”。
你可能会问:“不就是按 SQL 做吗?还需要方案?” 举个例子:如果你的 SQL 是SELECT * FROM user JOIN order ON user.id=order.user_id WHERE user.id>100,这里有 N 种做法:
- 方案 A:先把 user 表中 id>100 的记录挑出来,再和 order 表关联。
- 方案 B:先把 user 和 order 表全表关联,再过滤 id>100 的记录。
- 方案 C:如果 user.id 有索引,先通过索引找到 id>100 的记录,再关联 order 表。
这些方案的结果完全一样,但效率天差地别(比如方案 B 可能要扫描几百万行,方案 C 只扫几十行)。优化器的工作,就是在这些方案里选一个 “成本最低” 的 —— 他会计算每个方案的 “IO 成本”(读磁盘)和 “CPU 成本”(计算),然后 pick 最优解,生成 “执行计划(Execution Plan)”。
你可以用EXPLAIN + SQL查看这个执行计划,相当于直接问厨师长:“你打算怎么给我做菜?” 比如看type列是ALL(全表扫描,相当于厨师把所有食材都翻一遍)还是range(范围扫描,相当于直接去食材架的某一层找),就能知道优化器有没有 “偷懒”。
五、动手干!执行器:听话的 “厨师”
有了执行计划,终于轮到执行器(Executor) 出场了 —— 他就是后厨里 “说一不二” 的厨师,严格按照执行计划干活。
但厨师做菜前,得再确认一遍 “权限”:比如你要查user表,执行器会先问连接器:“这哥们儿有 user 表的 SELECT 权限吗?” 确认有了才动手,没有就直接报错(这一步是为了防止 “越权操作”,比如顾客明明只能点素菜,却想偷拿后厨的肉)。
权限确认后,执行器就开始调用存储引擎(Storage Engine) 的接口干活了。存储引擎是啥?相当于后厨的 “食材仓库”,负责真正和磁盘打交道,比如 InnoDB、MyISAM 都是常见的存储引擎(MySQL 支持插件式,你可以自己换 “仓库”)。
举个执行SELECT * FROM user WHERE id=1的例子:
- 执行器根据执行计划,调用 InnoDB 的接口:“给我查 user 表中 id=1 的记录。”
- 如果 id 有索引,InnoDB 会通过索引快速找到这条记录;如果没有,就全表扫描,一条一条找。
- InnoDB 把找到的记录返回给执行器。
- 执行器把记录整理成你要的格式(比如去掉你没选的列),然后返回给客户端(你的 Navicat、命令行等)。
如果是 UPDATE/DELETE 等写操作,流程类似,只是执行器会调用存储引擎的 “修改” 接口,并且存储引擎会涉及事务、日志(比如 redo log、undo log)等操作,确保数据修改的安全性(比如断电了也不会丢数据)。
六、总结:一条 SQL 的 “餐厅之旅” 全回顾
现在咱们把整个流程串起来,就像一场 “SQL 的餐厅冒险”:
- 前台(连接器):验证身份→分配权限→分配连接。
- (已退休)传菜员(查询缓存):看有没有现成的菜,没有就往后传。
- 点菜员(解析器):检查菜单语法→整理成标准化订单。
- 厨师长(优化器):制定最优做菜方案→生成执行计划。
- 厨师(执行器):确认权限→调用仓库(存储引擎)接口干活→返回结果。
至此,你敲下的那行 SQL,终于完成了它的 “使命”—— 从一行文字,变成了你想要的数据。
最后:给程序员的小建议
了解这个流程,不是为了 “炫技”,而是为了更好地优化 SQL。比如:
- 避免写 “长得差不多但又不一样” 的 SQL(比如多空格、大小写不一致),虽然查询缓存没了,但解析器和优化器也需要重新处理,浪费时间。
- 遇到 SQL 慢的时候,先用
EXPLAIN看看优化器的执行计划,是不是没走索引(比如type=ALL),然后针对性优化(比如加索引)。 - 尽量避免 “长连接泄露”,用完连接及时释放,不然数据库会被 “占座” 拖慢。
好了,关于 MySQL 执行 SQL 的流程就讲到这里,希望你下次敲 SQL 的时候,脑海里能浮现出这场 “餐厅大戏”—— 原来背后有这么多 “打工人” 在为你服务!
4276

被折叠的 条评论
为什么被折叠?



