没有索引时,数据库执行全表扫描——100万行数据需要100万次I/O操作,时间复杂度O(N)。而索引本质是排好序的B+树数据结构,将查找过程降为O(log N),百万级数据仅需约20次树节点查找。这就是索引能加速SQL查询的根本原因。
一个典型表现示例:执行SELECT * FROM users WHERE email='test@example.com',无索引时数据库逐行比对邮箱字段,耗时约800ms;给email字段建B+树索引后,查询直接定位到叶子节点,耗时仅0.5ms。性能差距超过1600倍。这个原理同样适用于ORDER BY和JOIN——索引已经排好序,排序步骤被省去;JOIN时大表的关联字段有索引,每次匹配变成树查找,而非全表扫描。
对于日常开发场景,这意味着:如果你的表有几十万行数据,一条慢查询从秒级优化到毫秒级,往往只需要加一个索引。但前提是得建对地方。
经常出现在WHERE、JOIN、ORDER BY、GROUP BY中的字段是首选。比如用户表每天有大量查询按email登录,email必须建索引。如果还经常按注册时间排序,再加一个created_at索引。
字段值重复率越低,索引效果越好。邮箱、用户ID等几乎唯一,索引能快速过滤;性别字段只有男/女两种值,建索引后依然需要扫描一半数据,几乎无效。注意:不要为低选择性字段单独建索引。
假设创建复合索引INDEX(a, b, c),他能高效支持:WHERE a=1、WHERE a=1 AND b=2、WHERE a=1 AND b=2 AND c=3。但WHERE b=2或WHERE c=3无法使用该索引,因为查询条件没有从最左列a开始。实际开发中,把最常用、选择性最高的列放在最前面。示例如下:
| 查询语句 | 能否使用复合索引 (a,b,c) | 原因 |
|---|---|---|
| WHERE a=1 AND b=2 | 是 | 从最左列a开始匹配,b也参与 |
| WHERE b=2 AND c=3 | 否 | 跳过了a列,索引失效 |
| WHERE a=1 ORDER BY b | 是 | a过滤后,b有序,避免文件排序 |
复合索引使用规则示例(数据来源:MySQL官方文档+B+树原理)
非决胜点:索引不是越多越好。每个非聚集索引都会拖慢写入操作(INSERT/UPDATE/DELETE),因为需同步更新索引结构。一个表建议控制在5个索引以内。定期用EXPLAIN分析执行计划,删除长期未使用的索引。
即使建了索引,查询写得不对也会让索引失效。以下是开发中最容易踩的3个坑:
- 对索引列使用函数——例如
WHERE YEAR(order_date)=2023,应改为范围查询WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'。函数阻止了索引的利用。 - 类型隐式转换——字符串字段用数值查询,如
WHERE phone=13800138000(phone是varchar),MySQL会隐式转换,索引失效。应写成WHERE phone='13800138000'。 - 前导通配符LIKE——
LIKE '%abc'无法使用索引,因为B+树只能按前缀匹配。LIKE 'abc%'则可以走索引。
另外,OR条件需要每个条件都有索引,否则可能全表扫描。一个小技巧:用覆盖索引避免回表。如果查询只涉及几个字段,把这几个字段建成复合索引,MySQL直接从索引中获取数据,无需回到原始数据行。例如SELECT username, age FROM users WHERE status=1,建INDEX(status, username, age)就是覆盖索引,性能提升明显。
后端开发者:在开发阶段就用EXPLAIN分析每条慢查询,为WHERE和JOIN字段建索引,复合索引把最常用列放最左,避免函数和隐式转换——闭眼选。数据分析师:如果你跑报表经常GROUP BY大量字段,考虑建宽表索引,或利用物化视图预计算,减少临时表开销。DBA:定期监控索引使用率,用OPTIMIZE TABLE整理碎片,清理无用的索引,平衡读写性能——唯一短板是写入频繁时索引过多会拖慢性能。
为什么加了索引查询还是慢?
可能原因:①索引建错了字段(低选择性);②查询条件未使用最左前缀;③使用了函数或隐式转换导致索引失效;④数据量太大且索引不够覆盖,需要回表。用EXPLAIN看type和key字段是否走索引。
复合索引顺序怎么定?
把最常用、过滤性最强的列放第一位。例如查询90%按user_id,剩余按user_id+status,则建INDEX(user_id, status)。如果还有按status单独查询,需另建INDEX(status)。
LIKE查询到底能不能用索引?
只有当通配符在末尾时(如'abc%')能用索引;通配符在开头('%abc')或中间('%abc%')无法使用B+树索引,建议改用全文索引或搜索引擎。
更新日期:2026年07月28日
来源