为什么MySQL的唯一索引(Unique Index)在写性能上略逊于普通索引?

P粉602998670

P粉602998670

2026-08-04

703人浏览

原创

唯一索引强制触发磁盘随机读,绕过change buffer,因需先校验唯一性而必须将索引页从磁盘读入内存;null值使唯一约束失效;应用层已幂等时加唯一索引属冗余。

为什么mysql的唯一索引(unique index)在写性能上略逊于普通索引?

唯一索引强制触发磁盘随机读,绕过 Change Buffer

普通索引写入时能缓存变更到 change_buffer,而唯一索引必须先校验唯一性——这意味着它得把目标索引页从磁盘读进内存,哪怕那页当前完全不在 buffer_pool 里。这个“先读再判”的动作彻底绕过了 change_buffer,每次写都多一次随机 I/O。

常见现象包括:innodb_buffer_pool_reads 突增、INSERT ... ON DUPLICATE KEY UPDATE 执行耗时明显升高、慢日志里频繁出现单条写入延迟超 100ms。

  • 机械硬盘(HDD)下影响更剧烈;SSD 上虽延迟低,但高并发离散写仍会拖累吞吐
  • innodb_change_buffering 对唯一索引完全无效,设成 allinserts 都不改变行为
  • 即使你调大了 innodb_change_buffer_max_size,它也只对普通索引起作用

NULL 值让唯一性约束形同虚设

MySQL 中 UNIQUE 索引允许任意多个 NULL,因为 NULL != NULL。这导致业务以为“加了唯一索引就绝不会重复”,结果插入 10 条 email IS NULL 全部成功。

检查方式很简单:SHOW CREATE TABLE t;,重点看约束定义是否含 UNIQUE NOT NULL。如果只是 UNIQUE 而没加 NOT NULL,那这个“唯一”在空值场景下根本不存在。

  • 联合唯一索引中,全为 NULL 的行也被视为可重复
  • 应用层若按“非空才校验”设计,数据库层的 UNIQUE 实际只覆盖部分数据,容易漏防

应用层已做幂等,再加唯一索引是双输

如果 Java 服务已用分布式锁 + 幂等表 + 事务确保 id_card 不重复,那再建 UNIQUE INDEX uk_id_card (id_card) 就纯属冗余:既拖慢写入,又抬高死锁概率,还让错误更难定位。

MySQL(Linux)
MySQL(Linux)

MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。

下载

Duplicate entry 'xxx' for key 'uk_id_card' 这类报错常被误判为数据污染或并发 bug,实际只是冗余校验撞上了应用层已拦住的重复请求。

  • 真正需要 UNIQUE 的只有两类刚性场景:外键引用列、或多系统直连 DB 且无法统一幂等
  • 高频写入字段(如日志表的 trace_id)优先选普通索引;去重要求由异步任务或应用兜底
  • 已有普通索引想升级为唯一索引前,务必先跑 SELECT COUNT(*) - COUNT(DISTINCT col) 检查隐性重复

查询性能几乎没差别,别为“快一点”选唯一索引

执行 SELECT id FROM user WHERE id_card = 'xxx' 时,唯一索引找到第一条就停,普通索引多扫一条确认无重复——但这只是内存里一次指针跳转+一次值比较,CPU 开销几纳秒,均摊后查性能差不到 0.1%。

真正影响查询的是回表开销:主键索引(聚簇索引)叶子节点存整行数据,UNIQUE 和普通索引都是二级索引,叶子节点只存索引列+主键值,查完还得回表一次。

  • 优化器对唯一索引的 type: consttype: eq_ref 提示,只在等值查询且确定单行返回时生效,不是普遍提速
  • 别因“语义上应该唯一”就默认加 UNIQUE——业务逻辑唯一 ≠ 数据库层必须强制唯一

唯一索引的核心代价藏在写路径里,而不是名字里那个“唯一”;最容易被忽略的,其实是 NULL 值和应用层幂等之间的边界模糊。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

mysql

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

2023.10.12

2473

8

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.27

449

4

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

2024.02.23

614

5

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

3970

10

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

2024.03.06

1346

4

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

2024.04.07

3562

11

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

2024.04.29

3515

6

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

642

5

sql中删除一列的命令是什么
sql中删除一列的命令是什么

在sql中,使用alter table语句可以删除一列,语法为:alter table table_name drop column column_name。想了解更多sql的相关内容,可以阅读本专题下面的文章。

2024.04.29

526

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 125人学习

使用phpenv集成环境安装极致CMS
使用phpenv集成环境安装极致CMS

共2课时 | 224人学习

phpEnv手册
phpEnv手册

共0课时 | 0人学习