mysql 8.0 及以后版本执行 select * from user where id = 1 不走查询缓存,因该模块已被彻底移除;流程依次为连接器校验身份、解析器与预处理器检查语法语义、优化器生成执行计划、执行器调用存储引擎获取数据。

MySQL 8.0 及以后版本执行一条 SELECT * FROM user WHERE id = 1,不会走查询缓存——这个模块已彻底移除,别再查配置项 query_cache_type 或试图启用它。
连接器先验身份,不是“连上就能查”
客户端发起 TCP 连接后,连接器 才开始工作:校验用户名密码、读取权限表、分配连接线程。关键点在于,权限检查只在连接建立时做一次;后续管理员改了权限,当前连接里不会更新。常见错误现象是:明明刚被授了 SELECT 权限,但执行语句仍报 Access denied for user——大概率是复用了旧连接,没重连。
- 长连接用多了会累积内存,建议应用层配连接池并设
wait_timeout自动断连 -
mysql -u root -p登录失败时,错误信息通常是Access denied for user 'root'@'localhost',优先检查密码或 host 匹配 - 连接成功后,
SHOW PROCESSLIST能看到该连接状态,Command列为Sleep表示空闲等待
解析器和预处理器联手筛掉非法 SQL
SQL 进入后先过 解析器:词法分析拆出 SELECT、id、= 等 token;语法分析确认结构合规(比如不能写成 SELECT FROM user 缺字段)。接着 预处理器 检查语义——表 user 存不存在?字段 id 在该表里有没有?用户对这张表有没有 SELECT 权限?
- 报错
Unknown table 'user'或Unknown column 'id' in 'field list'都发生在这一阶段,不涉及磁盘或索引 - 如果用了别名如
SELECT u.name FROM user u WHERE u.id = 1,预处理器会提前绑定u到实际表,避免执行时歧义 - 函数调用如
NOW()、COUNT(*)也在此阶段确认合法性,但不求值
优化器决定“怎么查”,不是“查什么”
优化器 的输出是执行计划(EXPLAIN 可见),它不关心业务逻辑,只算代价:走主键索引 id 扫描 1 行,还是全表扫描 10 万行?是否能用覆盖索引避免回表?JOIN 多张表时先查哪张?这些决策基于统计信息(INFORMATION_SCHEMA.STATISTICS)和成本模型。
-
EXPLAIN SELECT * FROM user WHERE id = 1若显示type: const,说明优化器认定这是主键等值查询,直接定位单行 - 加了
ORDER BY created_at LIMIT 10却没索引,优化器可能放弃索引而选文件排序,Extra列出现Using filesort - 统计信息过期(如大批量 INSERT 后未
ANALYZE TABLE)会导致优化器误判,选错索引
执行器调引擎拿数据,Buffer Pool 是第一道门
执行器 拿到执行计划后,按步调用存储引擎接口。以 InnoDB 为例:先查 Buffer Pool 是否有对应数据页;没有就从磁盘读入并缓存;再用 B+ 树索引定位记录。如果 SELECT * 且 id 是主键,直接返回整行;若查的是非索引列且没覆盖索引,还得根据主键“回表”二次查找。
- 慢查询往往卡在磁盘 IO——
SHOW ENGINE INNODB STATUS里的log i/o和buffer pool hit rate是关键指标 -
innodb_buffer_pool_size设太小会导致频繁换页,命中率低于 95% 就该调大 - 即使走了索引,
WHERE条件中用了函数如WHERE YEAR(create_time) = 2024,也会使索引失效,执行器被迫全扫
整个链路里最容易被忽略的,是预处理阶段的权限校验和优化器依赖的统计信息 freshness——它们不报错、不慢,但会让语句静默走错路径或干脆拒绝执行。











