mysql如何优化大表查询_mysql大数据量查询优化

来源:这里教程网 时间:2026-02-28 20:51:42 作者:

为什么加索引后查询还是慢?

不是所有字段加了索引就一定快。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 策略,每个环节都可能成为瓶颈。最容易被忽略的是:没有定期清理历史数据,或者误信“等业务增长后再优化”的说法——等真到了千万级,很多架构决策已经没法回退了。

相关推荐