你有没有遇到过这种情况:在公司系统里查一个客户信息,点下搜索后转圈圈好几秒才出结果。隔壁老王却说他查自己的客户几乎秒出,心里不禁嘀咕:难道他偷偷升级了电脑?其实问题可能不在电脑,而在数据库的索引上。
什么是索引?
可以把数据库想象成一本厚厚的电话簿。如果想找到“张伟”的电话,最笨的办法是从第一页开始翻,一页一页找,这种就是“全表扫描”。数据量小还好,一旦记录上了百万,那可真是等到花儿都谢了。
而索引就像是电话簿前面的目录,按姓氏拼音排序。你想找“Zhang”,直接翻到对应区域,几秒钟搞定。数据库里的索引干的就是这个事——给某一列或几列数据建个“快速查找表”,让查询不再盲目翻找。
加了索引,查询快得像飞
比如你经常用 WHERE user_id = 12345 来查订单,只要在 user_id 这一列加上索引,原本需要扫描几十万行的查询,可能只需要读取几页索引页就能定位到目标数据。
来看个例子:
CREATE INDEX idx_user_id ON orders (user_id);
这句 SQL 就是在 orders 表的 user_id 字段上创建了一个索引。之后所有基于 user_id 的查询都会优先走索引,速度提升可能是从5秒变成0.05秒。
不是所有字段都适合加索引
有人一听就急了:“那我把所有字段都加索引,岂不是全都能秒开?”想法很美,现实很骨感。索引不是免费的午餐,它会占用磁盘空间,更关键的是,每次插入、更新、删除数据时,数据库还得同步维护索引结构。
比如你有个日志表,每天写入十万条记录。如果这个表上有太多索引,写入速度会明显变慢,因为每写一条,就得把所有相关索引也更新一遍。这时候就得权衡:你是查得多,还是写得多?
复合索引有讲究
有时候你总是一起查两个条件,比如 WHERE status = 'paid' AND city = '北京'。这时候可以创建复合索引:
CREATE INDEX idx_status_city ON orders (status, city);
注意顺序很重要。这个索引对 status 单独查询有效,但对只查 city 的情况基本没用。就像电话簿按“姓+名”排序,你没法只按“名”来高效查找。
索引也可能失效
写了 WHERE name LIKE '%小明%',发现索引没生效,查询还是慢。这是因为模糊查询前面带百分号时,数据库无法利用索引的有序性,只能又回到全表扫描的老路。
类似的还有在字段上做函数计算,比如 WHERE YEAR(create_time) = 2023,即使 create_time 有索引,也会失效。正确做法是改成范围查询:
WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01'
这样才能让索引真正派上用场。
怎么看索引有没有起作用?
用 EXPLAIN 命令就能看查询执行计划。比如:
EXPLAIN SELECT * FROM orders WHERE user_id = 12345;
如果输出里的 key 字段显示了你建的索引名,说明命中了。如果是 NULL,那就得回头检查是不是写法有问题,或者索引根本没建对。
索引就像一把钥匙,用对了开门如入无人之境,用错了反而把自己锁在外面。理解它的脾气,才能让数据库真正听你指挥。