优化SQL性能需从查询逻辑、索引设计、表结构和执行过程四层面主动控制:只查必要字段、合理建索引并避免失效写法、优选JOIN而非相关子查询、分页用游标替代LIMIT偏移、精简表结构并冷热分离。

避免 SQL 语句性能问题,核心在于让 MySQL 尽可能少扫描数据、快定位结果、不额外计算。不是写得“能跑通”就行,而是要从查询逻辑、索引设计、表结构和执行过程四个层面主动控制。
只查需要的字段,别用 SELECT *
SELECT * 会强制读取整行所有列,即使只用其中一两个字段。尤其当表里有 TEXT、BLOB 或冗余历史字段时,I/O 和网络传输开销明显上升,还可能让本可走覆盖索引的查询退化为回表。
- 明确写出所需字段,如 SELECT user_id, name, status 而非 SELECT *
- 在 JOIN 查询中,只选择业务真正需要的字段,避免跨表拉取大量无用数据
- 应用层做字段裁剪(比如 API 返回精简 DTO),比数据库层全量返回再丢弃更高效
善用索引,但别迷信“加了索引就快”
索引不是万能钥匙。无效索引、低选择性索引、索引失效写法反而拖慢写入、增大维护成本。
- WHERE 条件中的字段优先建索引,组合条件按 最左前缀原则 设计联合索引顺序(如 WHERE a=1 AND b=2 AND c>3,推荐索引 (a,b,c),而非 (c,b,a))
- 避免在索引列上使用函数或表达式:WHERE YEAR(create_time) = 2024 无法走索引;应改写为 create_time BETWEEN '2024-01-01' AND '2024-12-31'
- 区分 等值查询 和 范围查询:联合索引中,范围条件(>、
- 定期用 EXPLAIN 检查执行计划,关注 type(最好为 const/ref/range)、key(是否命中索引)、rows(预估扫描行数)、Extra(是否出现 Using filesort / Using temporary)
控制 JOIN 和子查询的规模与方式
多表关联容易放大数据集,若驱动表选错或缺乏过滤条件,可能产生笛卡尔积或巨量中间结果。
- 确保 JOIN 字段类型一致、都有索引,且字符集/排序规则相同(否则隐式转换导致索引失效)
- 小表驱动大表:把过滤后结果集最小的表作为驱动表(MySQL 优化器通常能自动判断,但复杂查询建议用 STRAIGHT_JOIN 显式指定)
- 能用 JOIN 实现的逻辑,尽量不用相关子查询;相关子查询可能对主表每行都执行一次内层查询
- 大分页慎用 LIMIT m,n:OFFSET 过大时仍需扫描前 m 行。可改用“游标分页”,例如记录上一页最大 id,下一页查 WHERE id > last_id ORDER BY id LIMIT 20
合理设计表结构与数据生命周期
很多慢查询根源不在 SQL 写法,而在表本身——字段冗余、类型过大、历史数据堆积、缺乏分区或归档机制。
- 用合适的数据类型:用 TINYINT 代替 INT 存状态码,用 DATE 代替 DATETIME 存日期,减少存储和比较开销
- 拆分大字段:把访问频次低的大文本(如商品详情、日志内容)单独建附表,主表只保留关键摘要
- 冷热分离:对日志、订单历史等数据,按时间分区(PARTITION BY RANGE)或定期归档到历史库,保持主表体积可控
- 避免频繁 UPDATE 大字段:会引发整行重写和二级索引更新;必要时考虑标记删除+异步合并
不复杂但容易忽略。优化不是一劳永逸的事,而是在开发阶段就带着执行效率意识写 SQL,在上线前看执行计划,在运行中监控慢查询日志,持续迭代调整。











