%开头的LIKE无法走索引,导致全表扫描;应改用LIKE 'abc%'、函数索引、全文索引或ES;列名错误多因大小写、反引号缺失或别名作用域问题;GROUP BY报错源于ONLY_FULL_GROUP_BY模式,需合规改写SQL。
MySQL 慢查询日志里看到 SELECT ... WHERE ... LIKE '%xxx',为什么执行还慢?
因为 % 开头的 like 无法走索引,哪怕字段上有索引也白搭。这不是语法错,是语义陷阱——mysql 优化器直接放弃使用索引做范围扫描,转为全表扫描。
- 用
EXPLAIN看type字段:如果是ALL,基本就是全表扫了 - 把
LIKE '%abc'改成LIKE 'abc%'才可能命中索引(前提是索引列在最左前缀) - 真要查后缀,考虑加
REVERSE()函数建函数索引(MySQL 8.0+),比如CREATE INDEX idx_rev_name ON t1 ((REVERSE(name))),查时写WHERE REVERSE(name) LIKE REVERSE('abc') + '%' - 模糊匹配需求多,别硬扛,上
全文索引或ES更实际
执行报错 ERROR 1054 (42S22): Unknown column 'xxx' in 'where clause',但字段明明存在
常见于大小写混用、反引号缺失或别名作用域错乱。MySQL 在严格模式下对列名解析很较真,尤其跨子查询或 JOIN 时。
- 检查是否用了关键字当列名,比如
order、group,必须用反引号包住:`order` - 子查询里定义的别名,在外部 WHERE 中不可见,得挪到 HAVING 或外层再过滤
- 确认表别名有没有写错,比如写了
FROM users u,后面却用users.id而不是u.id - 大小写敏感取决于系统变量
lower_case_table_names,但列名一般不区分大小写;不过视图或临时表里若显式用了大写别名,就得严格匹配
为什么 GROUP BY 报错 ERROR 1055,而同样 SQL 在另一台机器上能跑?
这是 MySQL 5.7+ 默认开启 ONLY_FULL_GROUP_BY SQL 模式导致的,不是语法错,是合规性校验变严了。它要求 SELECT 列要么在 GROUP BY 中,要么是聚合函数包裹的。
- 临时绕过:执行
SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));(仅当前会话) - 长期方案:改 SQL,把非聚合字段从 SELECT 中去掉,或补进 GROUP BY,例如
SELECT user_id, MAX(created_at) FROM log GROUP BY user_id - 注意 ORM 自动生成的 SQL(如 Django 的
.values())容易触发这个错误,得看它生成的字段是否都出现在 GROUP BY 里 - 别盲目关全局模式,它能帮你提前发现逻辑歧义,比如你本意是按用户分组,却顺手 SELECT 了用户的 email 和 phone,而一个用户有多条记录时,这两个字段值不确定选哪条
ORDER BY 加了索引还是慢,EXPLAIN 显示 Using filesort
Using filesort 不代表一定慢,但说明没用上索引排序能力。根本原因是排序字段和 WHERE 条件字段没构成“最左前缀”连续索引。
- 假设查
WHERE status = 1 ORDER BY created_at,那索引得是(status, created_at),而不是单独的(created_at)或(status) - 如果
ORDER BY含多个字段,方向必须一致(都是 ASC 或都是 DESC),MySQL 8.0 才支持混合方向索引 - 有
LIMIT时,如果数据量大但只取前 10 条,filesort可能比索引扫描更省资源——优化器有时是对的,别急着调 - 覆盖索引能进一步减少回表,比如
SELECT id, name FROM t WHERE status=1 ORDER BY created_at,索引设为(status, created_at, id, name)
真正卡住的往往不是语法对不对,而是你写的 SQL 在数据库眼里“想表达什么”和你脑子里想的不一致。慢日志和 EXPLAIN 是翻译器,不是判官——得学会听它怎么念你的句子。

















