【面试】MySQL 面试常见优化问题
1. 为什么要建索引?索引一定能提高性能吗?
场景:一个表有上千万数据,查询
SELECT * FROM user WHERE age=25;
。问题:没有索引时会全表扫描,性能差。
解决方案:
给
age
建立普通索引,加快查询。但是索引不是越多越好:
插入、更新会更慢(需要维护索引)。
索引在选择性差(如
gender
字段只有男女)时可能没效果。
2. 覆盖索引是什么?为什么快?
场景:查询用户 ID 列表:
SELECT id FROM user WHERE age = 25;
说明:如果
age
上有索引,且查询只需要返回id
(在索引树中已包含),就不用回表。优化点:建组合索引
(age, id)
,查询时只走索引层,不访问数据页。
3. COUNT(*)
为什么慢?如何优化?
场景:统计
order
表的总数,有上千万行。问题:
COUNT(*)
会逐行扫描统计。优化方法:
如果是估算:用
EXPLAIN
的rows
。如果是精确计数:可以做 冗余表 或 缓存(Redis)。
InnoDB 会遍历二级索引+主键,不像 MyISAM 有行数缓存。
4. SQL 执行慢的常见原因?
场景:某个 SQL 在测试库很快,但生产库很慢。
常见原因:
没有走索引,发生全表扫描。
走了索引但选择性差,优化器放弃。
隐式转换(
WHERE phone = 1380000
,字段是VARCHAR
)。统计信息不准。
解决:
查看
EXPLAIN
。强制索引
FORCE INDEX
。优化字段类型,避免隐式转换。
更新统计信息
ANALYZE TABLE user;
5. 什么时候建组合索引?最左匹配原则怎么理解?
场景:经常有查询:
SELECT * FROM user WHERE country = 'CN' AND age = 25;
说明:
建组合索引
(country, age)
,比单列索引效率高。最左匹配:索引从最左边开始生效,
(a,b,c)
等价于(a)
、(a,b)
,但不会用(b)
单独索引。
优化点:
多条件查询,优先建组合索引。
条件字段顺序,选择性高的放前面。
6. 如何优化分页查询?
场景:
SELECT * FROM orders ORDER BY create_time LIMIT 100000, 20;
很慢,因为 MySQL 先扫描10万行再丢弃。
优化方法:
记录上一次的偏移:
SELECT * FROM orders WHERE id > 100000 LIMIT 20;
用覆盖索引 + join:
SELECT o.* FROM orders o JOIN (SELECT id FROM orders ORDER BY id LIMIT 100000, 20) t ON o.id = t.id;
7. 为什么要分库分表?分库分表后怎么查?
场景:
user
表超过 1 亿行,查询、写入都慢。优化思路:
分库分表:按
user_id % 8
拆成 8 张表。查询时通过中间件(ShardingSphere、Mycat)路由。
跨库统计问题 → 用 中间件聚合 或 异步汇总表。
8. InnoDB 和 MyISAM 的区别?为什么选择 InnoDB?
场景:设计电商订单表。
区别:
InnoDB:支持事务、行锁、MVCC,适合高并发。
MyISAM:表锁、无事务、计数快,适合只读场景。
面试要点:几乎所有业务型系统用 InnoDB,因为数据安全更重要。
9. 大表优化思路?
场景:订单表 5 亿行,查询和维护很慢。
优化点:
水平拆分(分库分表)。
冷热数据分离:历史数据归档。
索引优化:只建必要索引。
读写分离:主库写,从库读。
缓存:Redis 缓存热点数据。
10. 如何排查慢查询?
步骤:
打开慢查询日志:
slow_query_log = ON long_query_time = 1
用
EXPLAIN
分析执行计划。观察是否用到索引、rows 预估数。
用
SHOW PROFILE
查看耗时阶段。实在不行,用
pt-query-digest
工具分析日志。