admin管理员组文章数量:1438744
覆盖索引 vs 普通索引:只改一行 SQL,性能竟然快了 10 倍!
摘要
很多开发者在面对数据库性能瓶颈时,第一反应就是“加个索引”,但往往只是机械地添加普通索引,而忽略了更高效的优化方式,比如“覆盖索引”。本文将围绕覆盖索引与普通索引的核心差别、适用场景以及性能提升进行分析,并结合可运行的 SQL 示例进行对比,让你不仅知道怎么用,还知道为什么这么用。
引言
我们在做数据库查询优化时,经常听到一句话:“能用索引的地方都用索引。”但实际情况是,光有索引不一定就快,比如索引没选好、字段顺序不对,反而可能拖慢查询。尤其是覆盖索引这个东西,很多人听过但没真用过。那到底覆盖索引跟普通索引差在哪儿?为什么有人说它能极大提升查询性能?今天咱们就来好好聊聊。
什么是普通索引,什么是覆盖索引?
普通索引(Basic Index)
这是我们最常见的索引类型。你在某个字段上加了索引之后,查询会先通过索引定位数据,然后再回到原始表中取你需要的字段值。
这个“回原表取值”的过程,其实是要多走一步的,尤其在数据量大的时候,就会比较耗时。
举个例子:
代码语言:sql复制-- 创建表
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100),
age INT,
INDEX idx_name (name)
);
-- 查询语句
SELECT age FROM users WHERE name = 'Tom';
这里我们虽然在 name
上建了索引,但因为我们查询的是 age
,而 age
不在索引里,所以数据库会先通过 name
找到对应的主键,再去原表中查一遍 age
—— 这一步就叫做 回表。
覆盖索引(Covering Index)
覆盖索引的意思是:你要查的所有字段都在索引里了,根本不用回表了。
继续上面的例子,我们改成这样:
代码语言:sql复制-- 创建一个联合索引
CREATE INDEX idx_name_age ON users(name, age);
-- 查询语句
SELECT age FROM users WHERE name = 'Tom';
这时你会发现,name
和 age
都在索引 idx_name_age
里,MySQL 会直接在索引中完成整个查询,不用再回原表查数据,效率明显提升。
实战对比:覆盖索引 vs 普通索引
我们通过两个 SQL Demo 来感受一下区别。
建表和插入数据
代码语言:sql复制DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
email VARCHAR(100),
age INT,
INDEX idx_name (name),
INDEX idx_name_age (name, age)
);
-- 插入10万条数据
DELIMITER $$
CREATE PROCEDURE insert_users()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 100000 DO
INSERT INTO users(name, email, age)
VALUES (CONCAT('User', i), CONCAT('user', i, '@test'), FLOOR(RAND() * 100));
SET i = i + 1;
END WHILE;
END $$
DELIMITER ;
CALL insert_users();
普通索引的查询
代码语言:sql复制-- 使用普通索引,只查 age
EXPLAIN SELECT age FROM users WHERE name = 'User8888';
结果会显示:Using where; Using index condition
,说明会回表查数据。
覆盖索引的查询
代码语言:sql复制-- 使用覆盖索引(name, age)
EXPLAIN SELECT age FROM users WHERE name = 'User8888';
结果变成了:Using index
,表示 全程走索引,不回表,性能更优。
实际应用场景
- 报表查询: 如果你常常只需要查某个字段的统计,比如
SELECT age FROM users WHERE name = ?
,可以考虑用覆盖索引加速。 - 分页查询: 比如
SELECT id FROM table WHERE xxx ORDER BY id LIMIT 100
,如果只需要 id,那么走覆盖索引非常高效。 - 只读查询频繁场景: 像日志分析系统、搜索系统,查询量大但不常改,可以靠覆盖索引极大减少 IO 次数。
QA 环节
Q1:是不是所有查询都应该用覆盖索引?
不一定。覆盖索引会增加索引的体积,也可能造成写入性能下降。比如经常更新的字段加到联合索引里,会让更新变慢。所以一般用于读多写少的表。
Q2:创建覆盖索引是不是越多越好?
不是。要根据查询场景精确设计索引。盲目加索引会导致冗余,甚至让优化器做出错误选择,反而影响查询效率。
Q3:联合索引字段顺序重要吗?
很重要!MySQL 索引是有“最左前缀”原则的,比如你建了 (name, age)
索引,只能支持 WHERE name = ?
或 WHERE name = ? AND age = ?
,如果你只查 age
是用不到这个索引的。
总结
覆盖索引跟普通索引的本质差别,就是一个能少走一步(不回表),一个要多走一步(回表)。这种差别在小数据量上看不明显,但在大数据场景下,是能让查询快几倍甚至几十倍的。
掌握好覆盖索引的使用时机,可以让你写的 SQL 更“轻”、更快,配合好查询优化,性能提升不是小数点级别的。
未来展望
后续我们会继续聊聊更深层的优化方式,比如:
- 如何结合索引使用排序分页(ORDER BY + LIMIT)?
- 如何用执行计划看出是否用了覆盖索引?
- 聚簇索引和非聚簇索引对性能的影响?
- NoSQL 的索引机制又是怎么搞的?
本文标签: 覆盖索引 vs 普通索引只改一行 SQL,性能竟然快了 10 倍!
版权声明:本文标题:覆盖索引 vs 普通索引:只改一行 SQL,性能竟然快了 10 倍! 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1747571281a2712800.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论