为什么加索引后查询还是慢?
不是所有字段加了索引就一定快。MySQL 在大表中执行
SELECT *或含
ORDER BY、
GROUP BY的查询时,即使命中索引,也可能触发
Using filesort或
Using temporary——这两类操作会把数据拉到磁盘临时文件处理,性能断崖下跌。
实操建议:
用EXPLAIN看执行计划,重点检查
type是否为
range或更优(
ref/
eq_ref),避免
ALL或
index复合索引要遵循最左前缀原则:
WHERE a = ? AND b > ? ORDER BY c适合建
(a, b, c),但
(a, c, b)就无法支撑排序 避免在索引列上做函数操作,比如
WHERE YEAR(create_time) = 2024会让索引失效,改用
create_time BETWEEN '2024-01-01' AND '2024-12-31'
分页查第100万条以后的数据怎么不卡死?
LIMIT 1000000, 20这种写法会让 MySQL 扫描前 100 万行再丢弃,I/O 和 CPU 双重浪费。真实业务里,用户几乎不会翻到那么深的页,但接口没做限制就会被刷垮。
实操建议:
用游标分页(cursor-based pagination):记录上一页最后一条的id或
create_time,下一页查
WHERE id > ? ORDER BY id LIMIT 20如果必须用偏移量,给
LIMIT加硬限制,比如后端校验
offset ,超限直接返回错误对高偏移场景,可预生成分页映射表(如每天定时统计每万条的起始
id),用空间换时间
count(*) 为什么越来越慢?
MySQL 8.0 之前,
MyISAM表的
COUNT(*)是 O(1),但
InnoDB每次都得扫聚簇索引。表越大,扫描越久;加了
WHERE条件后更没法走优化。
实操建议:
不要在实时接口里调SELECT COUNT(*) FROM huge_table WHERE status = 1,改用近似值:查
information_schema.TABLES的
TABLE_ROWS(误差可能达 40%,但够看趋势) 对精确计数需求,用汇总表:建一张
table_counts,每次增删时用事务同步更新对应
status的计数 如果只是判断“有没有数据”,用
SELECT 1 FROM huge_table WHERE ... LIMIT 1,找到即停
大表 ALTER TABLE 怎么不锁表?
直接
ALTER TABLE huge_table ADD COLUMN x INT在 MySQL 5.6+ 默认会重建表(
copy算法),期间 DML 阻塞,线上服务直接雪崩。
实操建议:
优先用ALGORITHM=INPLACE支持的操作,例如加普通索引、改列默认值;执行前先查
SHOW CREATE TABLE确认引擎是
InnoDB对不支持 inplace 的变更(如加字段、改类型),用
pt-online-schema-change工具,它通过触发器双写+数据同步实现无锁 生产环境执行前,务必在从库上先试跑,观察
SHOW PROCESSLIST中是否出现长时间
Waiting for table metadata lock
大表优化没有银弹。索引设计、分页逻辑、统计方式、DDL 策略,每个环节都可能成为瓶颈。最容易被忽略的是:没有定期清理历史数据,或者误信“等业务增长后再优化”的说法——等真到了千万级,很多架构决策已经没法回退了。
