目录
- 一、UUID主键的缺陷
- 二、优化方案
UUID(Universally Unique IDentifier 通用唯一标识符),是一种常用的唯一标识符,在mysql中,可以利用函数uuid()来生产UUID。因为UUID可以唯一标识记录,因此有些场景可能会用来作为表的主键,但直接用UUID来作为主键可能存在性能缺陷,我们需要采取一些优化手段。
一、UUID主键的缺陷
在MySQL中,innodb是按照表的聚簇索引(主键)来组织数据存储的,也就是主键的顺序决定了数据存储的顺序。这也是为什么我们通常推荐用整型,自增的数字来作为表的主键,当新数据插入时,主键一定是最大的,只要放在叶子层中最后的数据页即可,对已有的数据不会有影响。
而如果用UUID来做主键,则会有2个缺陷:
- UUID的值是随机的,因此新插入的数据有可能会插到已有数据的中间,这会导致整个索引树的重新平衡和节点分裂,降低插入性能,数据量越大越严重。
- UUID是字符型,相对数字占用的存储空间很大,这意味着主键很大,而主键又会附加到所有的二级索引中,因此所有的索引都很臃肿,消耗额外的磁盘和内存资源,降低查询性能。
UUID的生成方式有很多版本,这里举2个最常用的:
- UUID V1: 通过时间戳和MAC地址来生成,可以生成顺序的UUID。
- UUID V4: 通过随机数来生成,无法生成顺序的UUID。
MySQL自带的函数uuid()是通过UUIDv1生成,因此上面第一个缺陷通常不存在,你需要注意的是某些应用是否会自己生成非顺序的UUID插入表中。
下面通过示例来看差别,我们创建两张结构一样的表,一张用数字作为主键,一张用UUID作为主键:
create table digital_pk(
id int auto_increment primary key,
serial int);
create table uuid_pk(
id varchar(36) default(uuid()) primary key,
serial int);
我们分别向2张表中插入5条数据:
insert into digital_pk(serial) values(1);
insert into digital_pk(serial) values(2);
insert into digital_pk(serial) values(3);
insert into digital_pk(serial) values(4);
insert into digital_pk(serial) values(5);
insert into uuid_pk(serial) values(1);
insert into uuid_pk(serial) values(2);
insert into uuid_pk(serial) values(3);
insert into uuid_pk(serial) values(4);
insert into uuid_pk(serial) values(5);
我们通过explain来查看索引的信息:
explain select * from digital_pk where id=1\G
explain select * from uuid_pk where id='71b49d70-7f98-11ee-a9a1-0050569c9844'\G
可以看到uuid作为主键的长度是146,而数字做主键的长度为4,这意味着当数据量非常大的时候,UUID的索引会非常臃肿,查询性能会很低。
二、优化方案
虽然通常不推荐使用UUID作为表的主键,但某些场景如果我们必须要用UUID作为主键,我们也可以通过一些方法来规避上述缺陷。
MySQL为了优化UUID的存储,专门提供了两个函数:
- uuid_to_bin(uuid, swap_flag),将字符型UUID转换为二进制UUID,转换后返回的数据类型是varbinary。
- bin_to_uuid(uuid, swap_flag),将二进制UUID转换为字符型UUID
在存储的时候用uuid_to_bin(uuid, swap_flag)将UUID由字符型转化为二进制,可以大大缩小索引的长度,函数中的swap_flag有2个取值:
- 0 代表转换后的数据依然是和UUID字符排序相同
- 1 代表转换后将UUID中的time-low和time-high部分(第一和第三组)交换位置,转换后数据可以按时间连续递增,对InnoDB的聚簇索引还会有性能提升。注意这个仅对UUID V1版本基于时间戳生成的UUID才有效,如果是其他类型的UUID,不会得到性能提升。
下面我们利用这个函数新建一个表uuid_pk_v2:
create table uuid_pk_v2( id binary(16) default(uuid_to_bin(uuid(),1)) primary key, serial int);
- 这里id列的数据类型变成了binary(16),同时uuid在存储时转换为二进制型存储。
插入1条数据
insert into uuid_pk_v2(serial) values(1);
select id, serial from uuid_pk_v2; select bin_to_uuid(id,1), serial from uuid_pk_v2;
- 直接查询是以16进制显示的数据,这对我们没有意义,我们需要用bin_to_uuid()函数将数据还原为字符串型UUID。
我们再看一下索引:
explain select * from uuid_pk_v2 where id=uuid_to_bin('a292725f-7fa1-11ee-a9a1-0050569c9844',1)\G
- 索引的长度从164缩短为16,只有原来的十分之一,这代表索引在磁盘和内存占用的空间也会缩小至十分之一,扫描速度会快的多。
- 因此,虽然在插入和查询的时候多了一层函数的处理,但是这可以完美解决前面UUID的两个缺陷,带来的性能提升是完全值得的。
到此这篇关于MySQL中UUID主键的优化小结的文章就介绍到这了,更多相关MySQL UUID主键优化内容请搜索编程网(www.lsjlt.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.lsjlt.com)!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756
相关文章
发现更多好内容- Java 中实现 MapReduce 的具体方法有哪些?(java实现mapreduce的方法是什么)
- 如何让 Java 的 settimeout 与线程池协同工作?(Java settimeout怎样与线程池配合)
- Java 中对象数组的定义及使用方式有哪些?(Java对象数组定义与用法有哪些)
- Java ClassLoader 的使用方法究竟是什么?(java classloader的使用方法是什么)
- Java 中 Bimap 的适用场景具体有哪些?(Bimap在Java中的适用场景有哪些)
- Java 和 Golang 在性能方面有哪些差异?(Java与Golang的性能差异)
- Java 中带参方法和无参方法的差异究竟体现在哪些方面?(java有参和无参的区别是什么)
- 如何在 Java 中创建 Date 对象?(java怎么创建date对象)
- 如何利用 Java Milo 开展网络编程?(如何使用Java Milo进行网络编程)
- 如何高效使用Redis客户端进行故障排查
猜你喜欢
AI推送时光机MySQL中UUID主键的优化小结
数据库2024-09-04Mysql主键UUID和自增主键的区别及优劣分析
数据库2022-06-01如何优化MySQL外键和主键之间的自动连接效率?
数据库2024-04-02浅谈MySQL的B树索引与索引优化小结
数据库2024-04-02MySQL中SQL优化、索引优化、锁机制、主从复制的方法
数据库2024-04-02服务器操作系统标准化:中小企业的关键竞争优势
数据库2024-02-21Java编程算法中,如何使用关键字框架来进行数据结构的优化?
数据库2023-08-19优化数据库性能:MySQL主从复制在集群技术中的最佳使用方法
数据库2023-10-22咦!没有更多了?去看看其它编程学习网 内容吧