数据库慢?先看索引!MySQL索引原理与实战

数据库慢?先看索引!MySQL索引原理与实战

你的网站最近变慢了。查了一圈,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=ALLrows=100000。加了索引后type=refrows=1

这就是索引的威力。


索引的常见误区

误区一:索引越多越好

错。

每个索引都会占用磁盘空间。一张100万行的表,加3-5个索引很常见,加几十个索引,磁盘空间可能比数据还大。

更重要的是,索引会降低写入速度。每次INSERTUPDATEDELETE,都要同时更新索引。索引越多,写入越慢。

原则:只为常用的查询条件加索引。不用的不加。

误区二:在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=ALLrows=1000000。全表扫描。

第三步:加索引

sql

CREATE INDEX idx_order_no ON orders(order_no);

第四步:再跑一次

sql

EXPLAIN SELECT * FROM orders WHERE order_no = 'ORDER123';

结果:type=refrows=1

实际查询时间:从3秒降到0.05秒。

快了多少?60倍。


什么时候不该用索引?

索引不是万能药。

  • 小表:几百行的表,全表扫描和用索引差别不大,索引反而占空间
  • 频繁写入的表:索引会拖慢写入速度,写多读少的场景慎加
  • 区分度低的列:比如性别(男/女),加索引意义不大
  • 频繁更新的列:索引要同步更新,成本高

最后一句:索引是数据库优化的第一把刀

很多人遇到数据库慢,第一反应是:

  • 升级服务器
  • 加缓存
  • 分库分表

这些都没错,但应该最后做。第一件要做的事是:看索引

因为加索引的成本最低,效果最明显。一行SQL,几秒钟,查询快几十倍。

下次你遇到数据库慢,先别慌。跑一遍 EXPLAIN,看看有没有 ALL。有的话,加个索引。

很可能,问题就解决了。

知识库

Ubuntu还是Debian?Linux发行版怎么选?

2026-4-3 13:48:18

知识库

深入了解轻量云服务器:适合小型企业的高性价比选择

2025-6-26 12:30:45

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧