
你的网站最近变慢了。查了一圈,CPU正常,内存够用,磁盘不忙。最后发现,是数据库查询慢。
一条SQL跑了3秒,用户等得都快关页面了。
你开始研究:加缓存?分库分表?升级服务器?
先别急。大多数慢查询,加个索引就能解决。今天把索引这事儿讲透,让你从“数据库慢”变成“秒开”。
先看一个反常识的数据
一张10万行的表,没有索引,查询一条数据可能要扫描全部10万行。加上索引,扫描次数可能只有10几次。
差了一万倍。
这就是索引的威力。它不是“优化”,是“降维打击”。
索引是什么?——书的目录
你去图书馆找一本书,没有目录,只能一排排书架翻。有目录,直接翻到第几页。
数据库索引,就是书的目录。它告诉数据库:“你要的数据在这,别全表扫了。”
底层原理(通俗版):MySQL的InnoDB引擎用B+树做索引。B+树的特点是:
- 矮胖:三层树能存几千万条数据
- 叶子节点存数据,非叶子节点存指针
- 查询时,从根节点一路找到叶子节点,I/O次数少
反常识点:B+树不是二叉树。二叉树太“高”,查一次要多次I/O。B+树一个节点存多个值,树矮,查询快。
怎么加索引?——实战命令
假设有一张用户表:
sql
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100),
age INT
);
加单列索引:
sql
CREATE INDEX idx_name ON users(name);
加唯一索引(值不能重复):
sql
CREATE UNIQUE INDEX idx_email ON users(email);
加复合索引(多个列):
sql
CREATE INDEX idx_name_age ON users(name, age);
查看索引:
sql
SHOW INDEX FROM users;
删除索引:
sql
DROP INDEX idx_name ON users;
怎么知道索引有没有生效?——EXPLAIN
加完索引,怎么知道SQL用上了?
用 EXPLAIN。
sql
EXPLAIN SELECT * FROM users WHERE name = '张三';
结果里看几列:
- type:ALL 是“全表扫描”,需要加索引。ref、range 是“用上索引了”。
- key:显示实际用了哪个索引。NULL表示没用到。
- rows:扫描了多少行。越小越好。
真实案例:一个10万行的表,type=ALL时rows=100000。加了索引后type=ref,rows=1。
这就是索引的威力。
索引的常见误区
误区一:索引越多越好
错。
每个索引都会占用磁盘空间。一张100万行的表,加3-5个索引很常见,加几十个索引,磁盘空间可能比数据还大。
更重要的是,索引会降低写入速度。每次INSERT、UPDATE、DELETE,都要同时更新索引。索引越多,写入越慢。
原则:只为常用的查询条件加索引。不用的不加。
误区二:在WHERE条件的列上加索引就行
不完全是。
还要考虑:
- 排序:
ORDER BY的列,有索引能避免文件排序 - 分组:
GROUP BY的列,有索引能加速 - 覆盖索引:如果查询的列都在索引里,MySQL不用回表查数据,更快
误区三:复合索引的列顺序不重要
错。
复合索引 (a, b) 和 (b, a) 是不同的。
最左前缀原则:复合索引只对从左开始的列组合有效。
比如 INDEX(a, b, c):
WHERE a = 1→ 用索引 ✅WHERE a = 1 AND b = 2→ 用索引 ✅WHERE b = 2→ 不用索引 ❌(a不在条件里)
所以,把区分度高的列放前面。比如 (status, create_time),status只有几个值,create_time有无数个值,应该把create_time放前面。
误区四:LIKE ‘%abc’ 能用索引
错。
LIKE 'abc%' 能用索引(前缀匹配)。LIKE '%abc' 不能用索引(通配符在前)。LIKE '%abc%' 也不能。
反常识点:很多人写 LIKE '%关键词%' 做搜索,结果全表扫描。真正的搜索不该这么写,应该用全文索引或Elasticsearch。
实战案例:一条慢查询的优化全过程
背景:订单表 orders,有100万行数据。查询订单号 ORDER123 的订单,跑了3秒。
第一步:找到慢查询
慢查询日志里看到这条SQL:
sql
SELECT * FROM orders WHERE order_no = 'ORDER123';
第二步:用EXPLAIN分析
sql
EXPLAIN SELECT * FROM orders WHERE order_no = 'ORDER123';
结果:type=ALL,rows=1000000。全表扫描。
第三步:加索引
sql
CREATE INDEX idx_order_no ON orders(order_no);
第四步:再跑一次
sql
EXPLAIN SELECT * FROM orders WHERE order_no = 'ORDER123';
结果:type=ref,rows=1。
实际查询时间:从3秒降到0.05秒。
快了多少?60倍。
什么时候不该用索引?
索引不是万能药。
- 小表:几百行的表,全表扫描和用索引差别不大,索引反而占空间
- 频繁写入的表:索引会拖慢写入速度,写多读少的场景慎加
- 区分度低的列:比如性别(男/女),加索引意义不大
- 频繁更新的列:索引要同步更新,成本高
最后一句:索引是数据库优化的第一把刀
很多人遇到数据库慢,第一反应是:
- 升级服务器
- 加缓存
- 分库分表
这些都没错,但应该最后做。第一件要做的事是:看索引。
因为加索引的成本最低,效果最明显。一行SQL,几秒钟,查询快几十倍。
下次你遇到数据库慢,先别慌。跑一遍 EXPLAIN,看看有没有 ALL。有的话,加个索引。
很可能,问题就解决了。




