MySQL 主键不推荐使用 UUID 的深层原因及解决方案

 更新时间:2026年01月08日 10:05:20   作者:萧曵 丶  
本文介绍了UUID在数据库中的存储空间、索引性能、页分裂、缓存效率等问题,并通过具体测试对比了UUID与其他主键类型(如INT和BIGINT)的性能差异,感兴趣的朋友跟随小编一起看看吧

1.存储空间问题

存储大小对比

主键类型存储大小示例值
BIGINT(自增)8字节1, 2, 3...
INT(自增)4字节1, 2, 3...
UUID(字符串)36字符(288位)uuid-xxxx-xxxx-xxxx
UUID(二进制)16字节二进制格式
-- UUID 的两种存储方式
CREATE TABLE users_uuid_str (
    id CHAR(36) PRIMARY KEY DEFAULT UUID(),  -- 36字节
    name VARCHAR(50)
);
CREATE TABLE users_uuid_bin (
    id BINARY(16) PRIMARY KEY,  -- 16字节,但仍然有其他问题
    name VARCHAR(50)
);

2.索引性能问题(最核心问题)

InnoDB 聚簇索引特性

-- InnoDB 表结构示例
-- 数据实际按主键顺序存储在磁盘上
-- 自增ID:数据物理存储是连续的
-- UUID:数据物理存储是随机的

性能影响对比

-- 场景:插入100万条数据
-- 使用自增ID
INSERT INTO table (name) VALUES ('name');  -- 直接追加到B+树末尾
-- 使用UUID
INSERT INTO table (id, name) VALUES (UUID(), 'name');  
-- 需要:1. 在B+树中寻找插入位置 2. 可能导致页分裂 3. 碎片化

3.页分裂与碎片化

页分裂过程

原始页(已满):[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
新插入UUID:需要插入到 5 和 6 之间
结果:
页1:[1, 2, 3, 4, 5]
页2:[uuid_value, 6, 7, 8, 9, 10]
问题:
1. 数据不再连续
2. 磁盘空间利用率下降
3. 查询需要更多磁盘I/O

4.缓存效率问题

InnoDB Buffer Pool 工作原理

-- 自增ID:连续的数据更容易一起被缓存
-- 读取用户1-100的数据可能只需要1-2次磁盘I/O
-- UUID:数据分散在不同页中
-- 读取100个用户数据可能需要100次磁盘I/O

5.具体性能测试对比

测试数据

-- 创建测试表
CREATE TABLE test_autoinc (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    data VARCHAR(100)
) ENGINE=InnoDB;
CREATE TABLE test_uuid (
    id CHAR(36) PRIMARY KEY DEFAULT UUID(),
    data VARCHAR(100)
) ENGINE=InnoDB;
-- 插入性能对比(100万行)
-- 自增ID:约 30-40秒
-- UUID:约 90-120秒(慢2-3倍)
-- 查询性能对比(范围查询)
SELECT * FROM test_autoinc WHERE id BETWEEN 100000 AND 200000;
-- 使用聚簇索引,高效
SELECT * FROM test_uuid WHERE id > 'xxxx';
-- 索引效率低,需要更多随机I/O

6.实际场景分析

适合使用UUID的场景

-- 分布式系统,需要离线生成ID
-- 数据需要合并的场景
-- 安全要求高,不希望暴露数据规模
-- 示例:移动设备离线数据同步

不适合使用UUID的场景

-- 高并发写入的OLTP系统
-- 需要频繁范围查询的业务
-- 数据量大的表(>1000万行)
-- 示例:电商订单、用户表、日志表

7.优化方案

方案1:组合使用

-- 使用自增ID作为主键,UUID作为业务ID
CREATE TABLE users (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,  -- 用于索引和关联
    uuid CHAR(36) UNIQUE NOT NULL DEFAULT UUID(),   -- 对外暴露
    name VARCHAR(50),
    INDEX idx_uuid(uuid)
);

方案2:有序UUID

-- 使用时间有序的UUID变体
-- MySQL 8.0+ 的 UUID_TO_BIN 函数
CREATE TABLE users (
    id BINARY(16) PRIMARY KEY DEFAULT (UUID_TO_BIN(UUID(), 1)),  -- 有序
    name VARCHAR(50)
);
-- 参数1:将时间部分移到前面,提高顺序性

方案3:雪花算法(Snowflake)

# 分布式ID生成算法(64位)
# 结构:时间戳(41位) + 机器ID(10位) + 序列号(12位)
# 优点:有序、分布式、高性能

8.MySQL 8.0 的改进

-- 生成有序UUID
SELECT UUID_TO_BIN(UUID(), 1);  -- 有序
SELECT UUID_TO_BIN(UUID(), 0);  -- 无序
-- 反向转换
SELECT BIN_TO_UUID(binary_uuid, 1);

9.监控指标

-- 查看碎片化程度
SELECT 
    table_name,
    data_length,
    index_length,
    data_free,
    ROUND(data_free/(data_length+index_length)*100, 2) as frag_percent
FROM information_schema.tables
WHERE table_schema = DATABASE();
-- 监控插入性能
SHOW ENGINE INNODB STATUS;

10.决策指南

何时可以使用UUID?

  • ✅ 数据量小(<100万行)
  • ✅ 插入频率低
  • ✅ 分布式系统必须使用
  • ✅ 数据合并需求
  • ✅ 安全要求高

应该避免使用UUID?

  • ❌ 高并发写入系统
  • ❌ 大数据量表
  • ❌ 频繁范围查询
  • ❌ 性能敏感系统
  • ❌ 磁盘空间有限

总结

        在大多数OLTP场景中,自增整数主键是最优选择。UUID主要问题是破坏InnoDB聚簇索引的顺序性,导致页分裂、碎片化、缓存效率低下等问题。如果必须使用UUID,应优先考虑有序UUID或组合方案,并监控性能影响。

到此这篇关于MySQL 主键不推荐使用 UUID 的深层原因的文章就介绍到这了,更多相关mysql主键不推荐使用uuid内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL中多表查询的方式总结

    MySQL中多表查询的方式总结

    本文详细介绍了多表查询的必要性、基础前提以及核心多表查询方式,包括JOIN连接查询(内连接、左外连接、右外连接、交叉连接)、子查询和联合查询,每种查询方式都有其适用场景和性能特点,并提供了实际项目中的应用示例和性能优化建议,需要的朋友可以参考下
    2025-12-12
  • MySQL分区表的基本入门教程

    MySQL分区表的基本入门教程

    这篇文章主要给大家介绍了关于MySQL分区表的基本入门教程,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • MySQL 数据库 增删查改、克隆、外键 等操作总结

    MySQL 数据库 增删查改、克隆、外键 等操作总结

    这篇文章主要介绍了MySQL 数据库 增删查改、克隆、外键 等操作,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • mysql5.7安装教程(windows)

    mysql5.7安装教程(windows)

    这篇文章主要为大家详细介绍了windows下mysql5.7安装教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • CentOS7环境下MySQL8常用命令小结

    CentOS7环境下MySQL8常用命令小结

    在进行MySQL的优化之前必须要了解的就是MySQL的查询过程,下面这篇文章主要给大家介绍了关于CentOS7环境下MySQL8常用命令的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • mysql 5.7 安装配置方法图文教程

    mysql 5.7 安装配置方法图文教程

    这篇文章主要为大家分享了mysql 5.7 安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • MySQL组成与常用工具详解

    MySQL组成与常用工具详解

    MySQL是一种关系型数据库管理系统,采用C/S架构,主要由mysqld_safe、mysqld、mysql、mysqldump等组件组成,它提供了多种客户端工具和管理工具,如mysqladmin、mycli等,帮助用户更好地管理和操作数据库,本文给大家介绍MySQL组成与常用工具,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • MySQL 中的 UPDATE 语句详解

    MySQL 中的 UPDATE 语句详解

    UPDATE 语句用于修改表中的数据,可以更新单行或多行数据,下面给大家介绍MySQL 中的 UPDATE 语句,感兴趣的朋友一起看看吧
    2025-05-05
  • Linux下实现MySQL数据备份和恢复的命令使用全攻略

    Linux下实现MySQL数据备份和恢复的命令使用全攻略

    这篇文章主要介绍了Linux下实现MySQL数据备份和恢复的命令使用全攻略,包括使用Mysqldump和LVM快照以及xtrabackup三种方法,倾力推荐!需要的朋友可以参考下
    2015-11-11
  • 详解Navicat远程连接mysql很慢

    详解Navicat远程连接mysql很慢

    这篇文章主要介绍了详解Navicat远程连接mysql很慢(以及数据库连接报错"Too many connections")解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11

最新评论