连接器先校验身份,再查权限表
你执行
mysql -u root -p后输入密码,连接器干的不是“连上就完事”,而是立刻查
mysql.user表确认账号是否存在、密码哈希是否匹配;通过后,再按
user → db → tables_priv → columns_priv顺序逐级查权限。哪怕你只查一张表的某个字段,只要
columns_priv里没开对应列的
SELECT权限,就会报
ERROR 1142 (42000): SELECT command denied to user,而不是语法错误。
常见踩坑点:
用SHOW PROCESSLIST能看到当前所有连接的
Id和
User,但看不到具体权限——权限是会话级缓存的,改了
mysql库的权限表后,必须执行
FLUSH PRIVILEGES或让客户端重连才生效
wait_timeout默认 8 小时,长连接空闲太久会被自动断开,应用层若没做重连逻辑,就会突然报
MySQL server has gone away权限验证失败时,错误信息里带
@'host'(比如
'root'@'192.168.1.100'),说明 MySQL 是按「用户名+来源 IP」组合鉴权的,不是单看用户名
解析器报错 = 语句根本没进优化器
当你写错
SELECT * FROM users WHERE id = 123;成
SELCT * FROM users WHERE id = 123;,或者查一个不存在的列
SELECT phone FROM users;,错误发生在解析器阶段——它做完词法分析(拆出关键字、标识符)和语法分析(检查结构是否符合
SELECT ... FROM ... WHERE ...规则)后直接报错,根本不会走到优化器或执行器。
这意味着:
EXPLAIN对这种语句无效,执行就报错,没法看执行计划 语法检查顺序严格:
SELECT → FROM → JOIN → ON → WHERE → GROUP BY → HAVING → UNION → ORDER BY → LIMIT,漏写
FROM或把
WHERE写在
GROUP BY前面,都会被解析器拦下 大小写和空格敏感:在 MySQL 5.7 及以前,
select * from t和
SELECT * FROM t是两个不同缓存 key(虽然 8.0 已删缓存,但解析器仍按字面值比对)
优化器选索引不认你写的 FORCE INDEX?正常
你加了
FORCE INDEX (idx_created_at),但
EXPLAIN显示还是走全表扫描?不是 MySQL 忽略你,而是优化器在
ANALYZE TABLE统计信息基础上做了成本估算:如果
created_at索引选择性差(比如只有 3 个不同值)、表又小(
Rows显示才几百行),它判断走索引回表反而比直接扫更快。
实操建议:
用SHOW TABLE STATUS LIKE 'orders'查
Rows和
Data_length,再用
SELECT COUNT(DISTINCT status) / COUNT(*) FROM orders算选择性,低于 0.01 就别指望它用这个字段索引
FORCE INDEX是绕过优化器的“硬指令”,但数据量突增后可能从加速变拖慢,线上慎用 真正可控的是建好复合索引:比如
WHERE status = ? ORDER BY created_at DESC,优先建
(status, created_at)而非单列索引
MySQL 8.0 起,查询缓存已彻底消失
别再查
query_cache_size或设
query_cache_type = 1——MySQL 8.0 把整个查询缓存模块(包括内存管理、失效逻辑、所有相关变量)全删了。你升级到 8.0 后如果还依赖缓存,要么换应用层缓存(Redis),要么靠 InnoDB 缓冲池(
innodb_buffer_pool_size)扛热数据。
为什么删?因为:
缓存 key 是 SQL 字符串全匹配,SELECT * FROM t和
SELECT * FROM t(多两个空格)就是两个缓存项 一张表任何
INSERT/UPDATE/DELETE,所有涉及该表的缓存全部失效,写多读少场景下命中率趋近于 0 多线程争抢缓存锁,高并发时反而成为瓶颈
现在真正的“缓存”只剩两层:InnoDB 的数据页缓存(由
innodb_buffer_pool_size控制),和操作系统的 page cache——它们不认 SQL,只认磁盘块,更底层也更稳定。
