SQL 优化核心思路:减少扫描的数据量、减少回表、避免全表扫描、合理利用索引、优化 SQL 写法、调整数据库配置。
一、索引优化(最常用)
- 建立合适索引
- where、join、order by、group by 后的字段适合建索引。
- 联合索引遵循最左前缀原则,把查询高频、筛选度高的字段放左边。
--联合索引:col1,col2,col3,where条件要尽量带上col1
create index idx_col1_col2_col3 on table(col1,col2,col3);
- 避免索引失效(重点)
- 不要对索引列做运算、函数、隐式类型转换
--失效,索引列做函数
select * from t where date(create_time)='2026‑08‑18';
--改写
select * from t where create_time >= '2026‑08‑18' and create_time < '2026‑08‑19';
like '%xxx'前缀通配符会失效;like 'xxx%'可以走索引or一边无索引容易失效,可以改用union all替代 or- 避免
is not null、!=、<>会导致放弃索引(数据分布不同情况不一样)
- 不要滥用索引
索引会加快查询,但减慢 insert/update/delete,每修改数据要维护索引。一张表索引不宜过多。 - 覆盖索引
查询的列全部在索引里,不需要回表读取原表,性能很高。
--索引包含id,name,直接从索引拿数据,不用回表
select id,name from t where id>100;
二、SQL 语句写法优化
- ** 不要 select ***,只查询需要的字段,减少数据传输,利于覆盖索引
--不好
select * from user;
--好
select id,name,phone from user;
- 分页优化,大 offset 不要直接 limit offset,size
--offset很大时性能差
select * from t limit 100000,10;
--优化:主键定位
select * from t where id>100000 limit 10;
- 避免大表 join,小表驱动大表
inner join,把数据量小的表放前面;尽量减少 join 的表数量。
- in 与 exists 选择
- 小集合用
in;子查询大结果集用exists。 - 避免
in()里面上万条数据。
- union 和 union all
union会去重排序,开销大;不需要去重优先用union all。 - where 条件过滤尽早执行
把能过滤大量数据的条件写在 where,不要放到 having。
having 是分组后过滤;where 是分组前过滤。
--不好
select count(*) from t group by age having age>20;
--更好
select count(*) from t where age>20 group by age;
- 减少排序
order by、group by、distinct会产生文件排序,尽量利用索引有序特性避免 filesort。
三、表结构设计优化
- 字段尽量小,选用合适数据类型,避免大字段(text/blob)频繁查询;大字段拆分到单独表。
- 尽量用主键 int/bigint,避免字符串做主键。
- 适当分表分库:数据量千万级别以上,考虑水平分表、垂直分表。
- 合理设置主键,InnoDB 主键建议自增,减少页分裂。
四、数据库层面优化
- explain 分析执行计划
explain select xxx from table where xxx;
重点看:
type:优先ref/range,尽量避免ALL全表扫描key:实际使用的索引,null 代表没用到索引rows:预估扫描行数,越小越好Extra:看到Using filesort(文件排序)、Using temporary(临时表)说明需要优化
- InnoDB 配置调优
innodb_buffer_pool_size:缓存数据与索引,机器内存 50‑70%,减少磁盘 IO。- 避免锁等待:大事务拆成小事务,减少行锁持有时间。
五、业务层面优化
- 缓存:热点数据放入 Redis,减少数据库查询。
- 读写分离:读多写少场景,主库写,从库承担查询。
- 避免一次性查询大量数据,分批查询,防止一次性把数据库打满。
- 统计报表不要直接跑在线业务库,同步数据到数库做统计。
六、常见坑总结
- 索引建了但是不走:函数、隐式转换、like 前缀 %、or 条件、统计信息不准。
- limit 大偏移分页慢。
- select * 浪费 IO,无法触发覆盖索引。
- 大事务、多表 join、临时表、文件排序。
简单排查步骤:先用explain看执行计划,确认是否全表扫描、索引是否生效,再改写 SQL 或者调整索引。
![]() |
Austin Liu 刘恒辉
Project Manager and Software Designer E-Mail:lzhdim@163.com Blog:https://lzhdim.cnblogs.com 欢迎收藏和转载此博客中的博文,但是请注明出处,给笔者一个与大家交流的空间。谢谢大家。 |




浙公网安备 33010602011771号