刚学数据库时,很多人看到“主键”和“索引”两个词总以为是一回事——毕竟建主键的时候,数据库自动给加了个索引;删了主键,那个索引也没了。但其实,它们根本不是同一个东西,只是经常“搭伙干活”罢了。
主键是规则,索引是工具
主键(PRIMARY KEY)说白了就是一张表里“唯一标识某一行”的硬性要求。比如用户表里的 user_id,不能重复、不能为 NULL,这是数据库强制执行的数据完整性规则。
而索引(INDEX)是数据库内部用来加速查询的“目录”。就像图书馆的索书号,不建索引也能查书,但得一本本翻;建了索引,就能直接定位到第几排第几列。
为什么主键会自动带索引?
因为数据库要高效验证“主键不能重复”这个约束。每次插入或更新数据时,它得快速判断:这个主键值以前有没有出现过?如果没索引,就得全表扫描一遍——上百万行的表,一次插入就要等好几秒,谁受得了?
所以 MySQL(InnoDB)、PostgreSQL 等主流引擎,默认给主键建一个聚簇索引(Clustered Index),把数据按主键顺序物理存放。这既是约束保障,也是性能优化,一箭双雕。
那没有主键,就一定没索引?
当然不是。你可以手动给任意字段建索引:
CREATE INDEX idx_email ON users(email);这时候 email 字段可能有重复(不是主键),但加了索引后,用 WHERE email = 'xxx@xxx.com' 查起来就快多了。
反过来:有索引,就等于能当主键?
错。普通索引默认允许 NULL 和重复值。比如你给 nickname 加个索引:
CREATE UNIQUE INDEX uk_nickname ON users(nickname);加上 UNIQUE 才能禁止重复,但依然允许 NULL(除非额外加 NOT NULL)。而主键从定义上就同时满足:非空 + 唯一 + 仅有一个。所以哪怕你建了个唯一索引,也不能直接当主键使——得显式用 ALTER TABLE ... ADD PRIMARY KEY 才行。
一个小实验帮你摸清区别
在 MySQL 里跑下面这几条命令:
CREATE TABLE test1 (id INT);
INSERT INTO test1 VALUES (1),(1); -- 成功!id 不是主键,也不唯一
ALTER TABLE test1 ADD PRIMARY KEY (id); -- 报错:Duplicate entry '1' for key 'PRIMARY'
DELETE FROM test1 WHERE id = 1 LIMIT 1;
ALTER TABLE test1 ADD PRIMARY KEY (id); -- 这次成功了你会发现:加主键失败,是因为数据本身不满足“唯一+非空”;而之前没主键时,哪怕数据重复,也完全不影响建普通索引或日常增删改查。
实际开发中容易踩的坑
有些同学为了省事,在日志表、埋点表这种“只写不查”的场景下,也硬塞个自增主键。结果磁盘占得多、写入变慢(因为要维护索引树),反而拖累性能。这类表完全可以不要主键,只在需要按时间范围查时,给 create_time 单独建个普通索引就行。
还有人误以为“只要加了索引,查询就一定快”。其实如果查询条件没用上索引字段(比如 WHERE status = 1 AND name LIKE '%abc%',而索引建在 name 上),或者数据分布极不均匀(比如 99% 的记录 status=1),MySQL 可能直接放弃走索引,改用全表扫描。