你有没有遇到过这样的情况:一个查询明明只想要用户ID为12345的那条记录,结果页面卡了三秒才出来?后台日志里还飘着一行警告:Query took 2842ms, examined 1.2M rows。这大概率不是服务器太老,而是数据库正在默默执行全表扫描。
全表扫描到底在干啥?
简单说,就是数据库不走捷径,老老实实从第一行翻到最后一行,挨个比对条件。比如执行:
SELECT * FROM orders WHERE user_name = '张三';而user_name字段又没建索引,MySQL就得把几百万条订单一条条拉出来,看看哪个叫张三——就像去图书馆找一本没编进目录的书,只能把所有书架全翻一遍。几个立竿见影的避坑法
加索引不是万能的,但不加索引基本是万万不能的。重点加在WHERE、JOIN、ORDER BY、GROUP BY后面出现的字段上。比如经常按手机号查用户:
ALTER TABLE users ADD INDEX idx_mobile (mobile);别盲目给所有字段都加索引。索引本身要占磁盘、拖慢写入速度,而且MySQL单表索引数太多反而会影响优化器选型。用EXPLAIN看看实际执行计划:
EXPLAIN SELECT * FROM products WHERE price > 99 AND status = 1;如果type列显示ALL,就是全表扫描;看到range或ref才算走上正道。还有个容易被忽略的点:隐式类型转换会悄悄让索引失效。比如user_id是BIGINT类型,你却写了:
SELECT * FROM users WHERE user_id = '12345';字符串和数字比较,MySQL会把每行user_id都转成字符串再比,索引直接作废。改成不带引号的12345就立马见效。另外,LIKE开头带百分号也是索引杀手:
SELECT * FROM logs WHERE content LIKE '%错误%';这种没法用B+树索引加速,真要模糊搜全文,不如交给Elasticsearch;日常查固定前缀,就写成LIKE '错误%',索引还能接上力。小技巧:用覆盖索引省掉回表
有时候你只需要几个字段,比如查用户昵称和注册时间:
SELECT nickname, created_at FROM users WHERE uid = 8899;如果在(uid, nickname, created_at)上建联合索引,数据库查完索引就直接把结果拼好了,连主键回表都省了——既快又轻量。最后提醒一句:上线前跑一遍慢查询日志,重点关注Rows_examined远大于Rows_sent的SQL。几十行的数据表无所谓,但一旦数据量涨到百万级,全表扫描就会从“偶尔卡一下”变成“每次点按钮都在祈祷”。