MySQL唯一索引和主键索引的区别有哪些(面试官常问)

 更新时间:2026年04月15日 08:55:06   作者:皮皮林551  
在数据库设计中,索引的选择与使用是优化查询性能的关键,下面这篇文章主要介绍了MySQL唯一索引和主键索引区别有哪些的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

面试考察点

  1. 索引类型理解:面试官不仅仅是想知道 "有什么区别",更是想考察你是否理解主键索引(聚簇索引)和唯一索引(二级索引)在存储结构上的根本差异。
  2. NULL 值处理:考察你是否清楚主键不允许 NULL,而唯一索引可以(但只能有一个),这是很多面试者容易忽略的细节。
  3. 性能优化意识:理解聚簇索引和非聚簇索引的查询效率差异,能否在设计表结构时做出正确选择。

核心答案

主键索引:一种特殊的唯一索引,每张表只能有一个,用于唯一标识每一行记录,InnoDB 中主键是 聚簇索引

唯一索引:保证索引列的值唯一,一张表可以有多个唯一索引,InnoDB 中唯一索引是 二级索引(非聚簇索引)

核心区别对比

对比维度主键索引(PRIMARY)唯一索引(UNIQUE)
数量限制每表 只能有 1 个每表 可以有多个
NULL 值不允许 NULL允许 NULL(但最多 1 个)
存储结构聚簇索引,叶子节点存完整数据二级索引,叶子节点存主键值
索引回表不需要回表需要回表(查询非索引列时)
创建语法PRIMARY KEY (col)UNIQUE KEY uk_name (col)
是否必须建议有,但不强制按需创建

一句话总结:主键是 唯一的聚簇索引,不允许 NULL;唯一索引是 可以有多个的非聚簇索引,允许 NULL。

深度解析

一、存储结构差异:聚簇索引 vs 二级索引

主键索引和唯一索引在 InnoDB 中的存储结构完全不同:

上图对比了主键索引和唯一索引的存储结构。关键区别在于:

  • 主键索引(聚簇索引) :叶子节点直接存储 完整的行数据,通过主键查询可以直接获取所有字段,无需回表
  • 唯一索引(二级索引) :叶子节点只存储 索引列的值 + 主键值,如果查询其他字段,需要拿着主键值回表查询聚簇索引

二、NULL 值处理差异

这是面试中的高频考点:

-- 创建测试表
CREATETABLEuser (
    idBIGINT PRIMARY KEY,           -- 主键,不允许 NULL
    email VARCHAR(50) UNIQUE,        -- 唯一索引,允许 NULL
    phone VARCHAR(20) UNIQUE         -- 唯一索引,允许 NULL
);
-- 主键测试:插入 NULL 会报错
INSERTINTOuser (id, email) VALUES (NULL, 'test@qq.com');
-- ❌ ERROR 1048: Column 'id' cannot be null
-- 唯一索引测试:允许 NULL,且 MySQL 中可以插入多个 NULL
INSERTINTOuser (id, email) VALUES (1, NULL);      -- ✅ 成功
INSERTINTOuser (id, email) VALUES (2, NULL);      -- ✅ 成功(MySQL 认为多个 NULL 不重复)
INSERTINTOuser (id, email) VALUES (3, 'a@qq.com'); -- ✅ 成功
INSERTINTOuser (id, email) VALUES (4, 'a@qq.com'); -- ❌ Duplicate entry

关键结论

  • 主键:绝对不允许 NULL,这是主键的基本约束
  • 唯一索引:允许 NULL,且 MySQL 中可以插入多个 NULL 值(因为 NULL != NULL

三、查询性能差异:回表问题

通过主键查询 vs 通过唯一索引查询的性能差异:

-- 表结构
CREATETABLEuser (
    idBIGINT PRIMARY KEY,
    email VARCHAR(50) UNIQUE,
    nameVARCHAR(50),
    age INT
);
-- 场景 1:通过主键查询
SELECT * FROMuserWHEREid = 1;
-- ✅ 直接走聚簇索引,一次查询即可获取完整数据
-- 场景 2:通过唯一索引查询所有字段
SELECT * FROMuserWHERE email = 'test@qq.com';
-- ⚠️ 需要回表:先查唯一索引得到 id,再回表查聚簇索引
-- 场景 3:通过唯一索引查询索引列(覆盖索引)
SELECT email FROMuserWHERE email = 'test@qq.com';
-- ✅ 覆盖索引,不需要回表

四、使用场景建议

场景推荐索引类型原因
标识每一行记录主键索引每表必须有唯一标识,推荐自增 BIGINT
用户邮箱不能重复唯一索引业务唯一性约束,允许未设置邮箱(NULL)
手机号唯一唯一索引允许用户暂未绑定手机号
身份证号唯一唯一索引允许 NULL(可能未录入)
联合唯一(用户 + 日期)联合唯一索引UNIQUE KEY uk_user_date (user_id, date)

最佳实践

-- 推荐:使用 BIGINT 自增主键
CREATETABLE orders (
    idBIGINTUNSIGNED AUTO_INCREMENT PRIMARY KEY,
    order_no VARCHAR(32) UNIQUENOTNULL,  -- 业务订单号,不允许 NULL
    user_id BIGINTNOTNULL,
    INDEX idx_user (user_id)
);
-- 不推荐:没有主键的表
-- MySQL 会自动选择一个非空唯一索引作为聚簇索引
-- 如果没有合适的,会生成一个隐藏的 6 字节主键

五、如果没有主键会怎样?

InnoDB 要求每张表必须有聚簇索引:

面试高频追问

  1. 追问一:为什么推荐使用自增主键而不是 UUID?
    • 答:自增主键是顺序插入的,B+ 树叶子节点顺序追加,不会产生页分裂;UUID 是无序的,插入会导致频繁页分裂,影响性能。此外,UUID 占用空间大(36 字符 vs 8 字节),降低索引效率。
  2. 追问二:一张表可以没有主键吗?
    • 答:可以,但 InnoDB 会自动选择一个非空唯一索引作为聚簇索引;如果没有合适的,会生成隐藏的 6 字节 ROW_ID。但强烈不建议这样做,应该显式定义主键。
  3. 追问三:联合主键和联合唯一索引有什么区别?
    • 答:本质区别和单列一样——联合主键是聚簇索引,不允许任何列为 NULL;联合唯一索引是二级索引,允许列为 NULL。

常见面试变体

  • "主键索引和唯一索引有什么区别?"
  • "聚簇索引和非聚簇索引的区别是什么?"
  • "MySQL 查询走唯一索引时为什么可能需要回表?"
  • "唯一索引允许 NULL 吗?主键呢?"

记忆口诀

主键 vs 唯一索引

  1. 主键聚簇:叶子存完整数据,查询不回表
  2. 唯一二级:叶子存主键值,查询需回表
  3. NULL 有别:主键不允许,唯一索引可以
  4. 数量不同:主键唯一一个,唯一索引多个

总结

主键索引是 聚簇索引,每表只能有一个,不允许 NULL,叶子节点存储完整行数据;唯一索引是 二级索引,可以有多个,允许 NULL(可多个),叶子节点存储主键值。查询时主键直接获取数据,唯一索引需要回表。推荐使用 BIGINT 自增主键,业务唯一约束用唯一索引。

到此这篇关于MySQL唯一索引和主键索引的区别有哪些的文章就介绍到这了,更多相关MySQL唯一索引和主键索引区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 对比MySQL中int、char以及varchar的性能

    对比MySQL中int、char以及varchar的性能

    在本篇文章中我们给大家分享了关于MySQL中int、char以及varchar的性能对比的相关内容,有兴趣的朋友们学习下。
    2018-10-10
  • MySQL数据库基础入门之常用命令小结

    MySQL数据库基础入门之常用命令小结

    这篇文章主要介绍了MySQL数据库基础入门之常用命令,结合实例形式分析了MySQL数据库管理、备份、日志常用操作命令与使用注意事项,需要的朋友可以参考下
    2020-05-05
  • MySQL 5.7安装好后打开命令行窗口闪退的解决方法

    MySQL 5.7安装好后打开命令行窗口闪退的解决方法

    这篇文章主要给大家介绍了关于MySQL 5.7安装好后打开命令行窗口闪退的解决方法,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧
    2018-12-12
  • mysql中如何去除小数点后面多余的0

    mysql中如何去除小数点后面多余的0

    这篇文章主要介绍了mysql 中去除小数点后面多余的0的方法 ,需要的朋友可以参考下
    2014-03-03
  • MySQL优化GROUP BY(松散索引扫描与紧凑索引扫描)

    MySQL优化GROUP BY(松散索引扫描与紧凑索引扫描)

    这篇文章主要介绍了MySQL优化GROUP BY(松散索引扫描与紧凑索引扫描),需要的朋友可以参考下
    2016-05-05
  • Mysql数据库之主从分离实例代码

    Mysql数据库之主从分离实例代码

    本篇文章主要介绍了Mysql数据库之主从分离实例代码,MySQL数据库设置读写分离,可以使对数据库的写操作和读操作在不同服务器上执行,提高并发量和相应速度。
    2017-03-03
  • sql模式设置引起的问题解决办法

    sql模式设置引起的问题解决办法

    这篇文章主要介绍了sql模式设置引起的问题解决办法,文章围绕主题展开详细内容,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-05-05
  • 详解监听MySQL的binlog日志工具分析:Canal

    详解监听MySQL的binlog日志工具分析:Canal

    Canal主要用途是基于MySQL数据库增量日志解析,提供增量数据订阅和消费,目前主要支持MySQL。接下来通过本文给大家介绍监听MySQL的binlog日志工具分析:Canal的相关知识,感兴趣的朋友一起看看吧
    2020-10-10
  • Linux上通过binlog文件恢复mysql数据库详细步骤

    Linux上通过binlog文件恢复mysql数据库详细步骤

    binglog文件是服务器的二进制日志记录着该数据库的所有增删改的操作日志,接下来通过本文给大家介绍linux上通过binlog文件恢复mysql数据库详细步骤,非常不错,需要的朋友参考下
    2016-08-08
  • 详解数据库_MySQL: mysql函数

    详解数据库_MySQL: mysql函数

    这篇文章主要介绍了数据库_MySQL: mysql函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03

最新评论